This notebook analyses the Part A data in terms of variable importance using a random forest model based on conditional inference trees and a conditional permutation variable importance algorithm.

Setup

Load packages

# load packages
library(tidyr)
library(ggplot2)
library(party)
library(conflicted)
library(tidyverse)
library(openxlsx)
library(caret)
library(viridis)
library(cowplot)
# set package parameters
theme_set(theme_bw())

# plot colour scheme

mycolourlist = list(c(0, 102, 255), c(0, 204, 153), c(255, 0, 102), c(74, 111, 152), c(251, 164, 49), c(204, 153, 255), c(90, 192, 255), c(80, 245, 233), c(255, 90, 192), c(164, 201, 242), c(255, 254, 139), c(255, 243, 255))
mycolours = matrix()

for (ii in 1:length(mycolourlist)){
  mycolours[ii] = rgb(mycolourlist[[ii]][1]/255,
                      mycolourlist[[ii]][2]/255,
                      mycolourlist[[ii]][3]/255)
}

# toggle to save plots
saveplots = TRUE

if (saveplots){
  # set output plot directory
  choose.files(caption="Just cancel this", filters=matrix(data=c(" ", " "), ncol=2))  # workaround for bug in RTerm choose.dir
  outFigPath <- utils::choose.dir(caption="Select output folder to save plots '03 Experiment\\Experiment 1\\Analysis\\Plots'")
  
  if (!dir.exists(file.path(outFigPath, "svg"))){dir.create(file.path(outFigPath, "svg"))}
  if (!dir.exists(file.path(outFigPath, "pdf"))){dir.create(file.path(outFigPath, "pdf"))}
  
}

# toggle to save data
savedata = TRUE

if (savedata){
  # set output plot directory
  if (saveplots==FALSE){
    choose.files(caption="Just cancel this", filters=matrix(data=c(" ", " "), ncol=2))  # workaround for bug in RTerm choose.dir
  }
  outDataPath <- utils::choose.dir(caption="Select output folder to save data '03 Experiment\\Experiment 1\\Analysis\\R'")
}
 

Import data and wrangle

Part A


stimDataApath <- utils::choose.files(caption=r"(Select refmap_listest1_testdataA_ByStim.csv from 03 Experiment\Experiment 1\Analysis\PostProcess)",
                                     filters=matrix(data=c("refmap_listest1_testdataA_ByStim.csv", "refmap_listest1_testdataA_ByStim.csv"), ncol=2))

stimNoticeDataApath <- utils::choose.files(caption=r"(Select refmap_listest1_testdataANoticeFilt_ByStim.csv from 03 Experiment\Experiment 1\Analysis\PostProcess)", filters=matrix(data=c("refmap_listest1_testdataANoticeFilt_ByStim.csv", "refmap_listest1_testdataANoticeFilt_ByStim.csv"), ncol=2))

stimDataA <- utils::read.csv(stimDataApath, header=TRUE)
stimNoticeDataA <- utils::read.csv(stimNoticeDataApath, header=TRUE)

colnames(stimDataA)[1] <- "Stimulus"
colnames(stimNoticeDataA)[1] <- "Stimulus"

# make response proportions into percentages
stimDataA[['HighAnnoyPc']] <- stimDataA[['HighAnnoyProp']]*100
stimDataA[['dHighAnnoyPc']] <- stimDataA[['dHighAnnoyProp']]*100

# make response proportions into percentages
stimNoticeDataA[['HighAnnoyPcFilt']] <- stimNoticeDataA[['HighAnnoyPropFilt']]*100
stimNoticeDataA[['dHighAnnoyPcFilt']] <- stimNoticeDataA[['dHighAnnoyPropFilt']]*100
stimNoticeDataA[['NoticedPcFilt']] <- stimNoticeDataA[['NoticedPropFilt']]*100
# function to encode categorical to ordinal numeric variables
encode_ordinal <- function(x, order=unique(x)) {
  x <- as.numeric(factor(x, levels=order, exclude=NULL, order=TRUE))
  x
}

# definition of ordinal variable levels
SNRCatsA <- c("No UAS", "-16", "-10", "-4", "2", "8")
UASLAeqCatsA <- c("No UAS", "42", "48", "54", "60")

The aggregated data by stimulus are assigned to a dataframe, relevant categorical variables are converted to ordinal, and then the variable subset of interest is selected, NA rows dropped (ie, the ‘no UAS’ stimuli, as the conditional variable importance algorithm cannot currently handle NA values, which are present in all the UAS dB metrics), and a formula assigned.


stimDataANum <- data.frame()

stimDataANum <- cbind(stimDataA[, 'Stimulus'],
                      stimDataA[, which(colnames(stimDataA)=="UASLAeq"):
                                  which(colnames(stimDataA)=="SNRlevel")],
                      stimDataA[, "IntermitRatioMaxLR", drop=F],
                      stimDataA[, which(colnames(stimDataA)=="UASLAeqMaxLR"):
                                  which(colnames(stimDataA)=="UASImpulsSHM05ExMaxLR")],
                      stimDataA[, which(colnames(stimDataA)=="LAeqLAF90diff"):
                                  which(colnames(stimDataA)=="dImpulsSHM05ExMaxLR")],
                      stimDataA[, which(colnames(stimDataA)=="ValenceMedian"):
                                  which(colnames(stimDataA)=="dHighAnnoyProp")],
                      stimDataA[, which(colnames(stimDataA)=="HighAnnoyPc"):
                                  which(colnames(stimDataA)=="dHighAnnoyPc")])

# remove duplicated variables
stimDataANum <- subset(stimDataANum, select = -c(UASLAeqMaxLR, UASLAEMaxLR))

colnames(stimDataANum)[1] <- "Stimulus"

# make the categorical outcome variables numerical dummy factors
# stimDataANum[['SNRlevel']] <- encode_ordinal(stimDataA[['SNRlevel']], order=SNRCatsA)
# stimDataANum[['UASLAeq']] <- encode_ordinal(stimDataA[['UASLAeq']], order=UASLAeqCatsA)

# make the discrete ordinal outcome variables factors
stimDataANum[['ValenceMedian']] <- factor(stimDataANum[['ValenceMedian']], levels=c(1, 2, 3, 4, 5), order=TRUE)
stimDataANum[['ArousalMedian']] <- factor(stimDataANum[['ArousalMedian']], levels=c(1, 2, 3, 4, 5), order=TRUE)
stimDataANum[['AnnoyMedian']] <- factor(stimDataANum[['AnnoyMedian']], levels=c(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10), order=TRUE)
stimDataANum[['dValenceMedian']] <- factor(stimDataANum[['dValenceMedian']], levels=c(-4, -3, -2, -1, 0, 1, 2, 3, 4), order=TRUE)
stimDataANum[['dArousalMedian']] <- factor(stimDataANum[['dArousalMedian']], levels=c(-4, -3, -2, -1, 0, 1, 2, 3, 4), order=TRUE)
stimDataANum[['dAnnoyMedian']] <- factor(stimDataANum[['dAnnoyMedian']], levels=c(-10, -9, -8, -7, -6, -5, -4, -3, -2, -1,
                                                                                 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10), order=TRUE)

stimNoticeDataANum <- data.frame()

stimNoticeDataANum <- cbind(stimNoticeDataA[, 'Stimulus'],
                            stimNoticeDataA[, which(colnames(stimNoticeDataA)=="UASLAeq"):
                                              which(colnames(stimNoticeDataA)=="SNRlevel")],
                            stimNoticeDataA[, "IntermitRatioMaxLR", drop=F],
                            stimNoticeDataA[, which(colnames(stimNoticeDataA)=="UASLAeqMaxLR"):
                                              which(colnames(stimNoticeDataA)=="UASImpulsSHM05ExMaxLR")],
                            stimNoticeDataA[, which(colnames(stimNoticeDataA)=="LAeqLAF90diff"):
                                              which(colnames(stimNoticeDataA)=="dImpulsSHM05ExMaxLR")],
                            stimNoticeDataA[, which(colnames(stimNoticeDataA)=="NoticedTotalFilt"):
                                              which(colnames(stimNoticeDataA)=="NoticedPcFilt")])

stimNoticeDataANum <- subset(stimNoticeDataANum, select = -c(UASLAeqMaxLR, UASLAEMaxLR))

colnames(stimNoticeDataANum)[1] <- "Stimulus"

# make the categorical outcome variables numerical dummy factors
# stimNoticeDataANum[['SNRlevel']] <- encode_ordinal(stimNoticeDataA[['SNRlevel']], order=SNRCatsA)
# stimNoticeDataANum[['UASLAeq']] <- encode_ordinal(stimNoticeDataA[['UASLAeq']], order=UASLAeqCatsA)

Random forest functions

Write a function to train a conditional-inference random forest (crf) model on input data according to input formula, iterate over input random seeds, average error and variable importance metrics, and output metrics with plotted

Averaging over multiple random seeds


multi_crfReg <- function(dataIn, iVars, dVar, seeds, ntree, mtry, permImpCondThres=0.95, minsplit=20, minbucket=7, nperm=1){
  # initialise variables
  crfOOBErrAll <- 0
  crfOOBRMSE <- 0
  crfOOBMAE <- 0
  crfOOBErrR2 <- 0
  crfMarPermImpVals <- 0
  crfConPermImpVals <- 0
  crfMarPermImpValsPerTree <- data.frame()
  crfConPermImpValsPerTree <- data.frame()
  
  for (iters in 1:length(seeds)){
    
    # formula for regression
    formVars <- reformulate(iVars, dVar)
    
    # set random seed
    set.seed(seeds[iters])
    # train crf model
    crfModel <- party::cforest(formVars, data=dataIn,
                               controls=party::cforest_unbiased(ntree=ntree,
                                                                mtry=mtry,
                                                                minsplit=minsplit,
                                                                minbucket=minbucket))
    
    # get OOB predictions
    crfModelOOB <- predict(crfModel, OOB=TRUE, type='response')
    
    # get OOB error
    crfModelOOBErr <- as.numeric(as.matrix(as.numeric(as.matrix(crfModelOOB))
                                            - as.numeric(as.matrix(crfModel@data@env$response[[names(crfModel@data@env$response)]]))))

    # OOB RMSE, error quartiles and Rsquared
    crfOOBRMSE <- crfOOBRMSE + sqrt(mean(crfModelOOBErr^2))
    crfOOBMAE <- crfOOBMAE + mean(abs(crfModelOOBErr))
    crfOOBErrR2 <- crfOOBErrR2 + cor(as.numeric(as.matrix(crfModelOOB)),
                                     as.numeric(as.matrix(crfModel@data@env$response[[names(crfModel@data@env$response)]])))^2

    # set random seed
    set.seed(seeds[iters])

    # set random seed
    set.seed(seeds[iters])
    # conditional variable permutation importance
    crfConPermImp <- permimp::permimp(crfModel, nperm=nperm, conditional=TRUE, threshold=permImpCondThres, progressBar=FALSE)
    
    crfConPermImpVals <- crfConPermImpVals + crfConPermImp$values
    crfConPermImpValsPerTree <- rbind(crfConPermImpValsPerTree, crfConPermImp$perTree)
  }
  
  # average metrics
  crfOOBErrAll <- crfOOBErrAll/length(seeds)
  crfOOBRMSE <- crfOOBRMSE/length(seeds)
  crfOOBMAE <- crfOOBMAE/length(seeds)
  crfOOBErrR2 <- crfOOBErrR2/length(seeds)
  crfConPermImpVals <- data.frame(CondPermImp=sort(crfConPermImpVals/length(seeds), decreasing=TRUE))
  #crfConPermImpValsMn <- sort(colMeans(crfConPermImpValsPerTree), decreasing=TRUE)  # mean of conditional variable importance values per tree (same as crfConPermImpVals)
  crfConPermImpValsQtl <- data.frame(apply(crfConPermImpValsPerTree, 2, quantile, probs=c(0.25, 0.50, 0.75)))
  
  resultsOut <- list('OOB_RMSE'=crfOOBRMSE, 'OOB_MAE'=crfOOBMAE, 'Rsquared'=crfOOBErrR2, 'conditional_permimp'=crfConPermImpVals,                      'conditional_permimp_perTree'=crfConPermImpValsPerTree, 'conditional_permimp_qtl'=crfConPermImpValsQtl)
  return(resultsOut)
}

Comparing rankings from two seeds


crfReg <- function(dataIn, iVars, dVar, seeds, ntree, mtry, permImpCondThres=0.95, minsplit=20, minbucket=7, nperm=1){
  # initialise variables
  crfOOBErrAll <- 0
  crfOOBRMSE <- 0
  crfOOBMAE <- 0
  crfOOBErrR2 <- 0
  crfMarPermImpVals <- 0
  crfConPermImpVals <- 0
  crfMarPermImpValsPerTree <- data.frame()
  crfConPermImpValsPerTree <- data.frame()

  # formula for regression
  formVars <- reformulate(iVars, dVar)
  
  for (iters in 1:length(seeds)){
  
    # set random seed
    set.seed(seeds[iters])
    # train crf model
    crfModel <- party::cforest(formVars, data=dataIn,
                               controls=party::cforest_unbiased(ntree=ntree,
                                                                mtry=mtry,
                                                                minsplit=minsplit,
                                                                minbucket=minbucket))
    
    # conditional variable permutation importance
    crfConPermImp <- permimp::permimp(crfModel, nperm=nperm, conditional=TRUE, threshold=permImpCondThres, progressBar=FALSE)
    
    crfConPermImpVals <- crfConPermImp$values
    
    if (iters == 1){
      crfConPermImpVals1 <- data.frame(CondPermImp=sort(crfConPermImpVals, decreasing=TRUE))
      crfConPermImpValsPerTree1 <- crfConPermImp$perTree
      crfConPermImpValsQtl1 <- data.frame(apply(crfConPermImpValsPerTree1, 2, quantile, probs=c(0.25, 0.50, 0.75)))
      
      # get OOB predictions
      crfModelOOB <- predict(crfModel, OOB=TRUE, type='response')
      
      # get OOB error
      crfModelOOBErr <- as.numeric(as.matrix(as.numeric(as.matrix(crfModelOOB))
                                              - as.numeric(as.matrix(crfModel@data@env$response[[names(crfModel@data@env$response)]]))))
      
      # OOB RMSE, error quartiles and Rsquared
      crfOOBRMSE <- sqrt(mean(crfModelOOBErr^2))
      crfOOBMAE <- crfOOBMAE + mean(abs(crfModelOOBErr))
      crfOOBErrR2 <- cor(as.numeric(as.matrix(crfModelOOB)),
                                    as.numeric(as.matrix(crfModel@data@env$response[[names(crfModel@data@env$response)]])))^2

      }
    
    else{
      crfConPermImpValsN <- data.frame(CondPermImp=sort(crfConPermImpVals, decreasing=TRUE))
      
      nVarImpChecks <- min(max(sum(crfConPermImpVals1 >= crfConPermImpVals1$CondPermImp[1]*0.1),
                               sum(crfConPermImpValsN >= crfConPermImpValsN$CondPermImp[1]*0.1)), 4)  # number of variable importance values with a value at least 10% of the highest importance
      if (sum(rownames(crfConPermImpVals1)[1:nVarImpChecks] != rownames(crfConPermImpValsN)[1:nVarImpChecks]) > 0){
        warning("Permutation importance rank order within 10% of max differs between seeds: increase number of trees ('ntree') or number of permutations ('nperm'), or subsample of features ('mtry')")
      }
      else{
        resultsOut <- list('OOB_errors'=crfModelOOBErr, 'OOB_RMSE'=crfOOBRMSE, 'OOB_MAE'=crfOOBMAE, 'Rsquared'=crfOOBErrR2, 'conditional_permimp'=crfConPermImpVals1, 'conditional_permimp_perTree'=crfConPermImpValsPerTree1, 'conditional_permpimp_qtl'=crfConPermImpValsQtl1)
        return(resultsOut)
      }
      
    }
    
  }

}

Hyperparameter tuning

mtryTune <- function(dataIn, iVars, dVar, seed, ntrees, minsplit=20, minbucket=7){
  
  formVars <- reformulate(iVars, dVar)
  
  # set mtry values and corresponding iVars/mtry ratios
  iVars_mtrys <- c(10.5, 5.25, 3.5, 2.75, 2.25, 1.75, 1.5, 1.25)
  mtrys <- as.integer(length(iVars)/iVars_mtrys)
  iVars_mtrys <- iVars_mtrys[mtrys >= 2]  # remove 0 or 1 values
  mtrys <- mtrys[mtrys >= 2]  # remove 0 or 1 values
  
  # remove any duplicated values
  iVars_mtrys <- iVars_mtrys[!(duplicated(mtrys) | duplicated(mtrys, fromLast = TRUE))]
  mtrys <- mtrys[!(duplicated(mtrys) | duplicated(mtrys, fromLast = TRUE))]

  # ensure mtrys is less than length(iVars)
  iVars_mtrys <- iVars_mtrys[mtrys < length(iVars)]
  mtrys <- mtrys[mtrys < length(iVars)]

  resRMSEMap = matrix(data=NA, nrow=length(mtrys), ncol=length(ntrees))
  resRsquaredMap = matrix(data=NA, nrow=length(mtrys), ncol=length(ntrees))
  resMAEMap = matrix(data=NA, nrow=length(mtrys), ncol=length(ntrees))
  
  for (ii in seq(1, length(ntrees))){
    set.seed(seed)
    ntree = ntrees[ii]
    tuneMod <- caret::train(formVars,
                            data=dataIn,
                            method='cforest',
                            controls=party::cforest_unbiased(ntree=ntree,
                                                             minsplit=minsplit,
                                                             minbucket=minbucket),
                            tuneGrid=data.frame(.mtry=mtrys),
                            trControl = trainControl(method = "oob"))
    
    tuneMod$results <- cbind(tuneMod$results, data.frame(iVars_mtrys=iVars_mtrys))
    
    print(tuneMod$results)
    print(tuneMod$bestTune)
    
    resRMSEMap[, ii] = tuneMod$results$RMSE
    resRsquaredMap[, ii] = tuneMod$results$Rsquared
    resMAEMap[, ii] = tuneMod$results$MAE
    
  }
  
  
  # convert to data frames with mtry as row names and ntree as column names, and convert to long format using tidyverse
  resdfRMSEMap <- as.data.frame(resRMSEMap)
  rownames(resdfRMSEMap) <- mtrys
  colnames(resdfRMSEMap) <- ntrees
  resdfRsquaredMap <- as.data.frame(resRsquaredMap)
  rownames(resdfRsquaredMap) <- mtrys
  colnames(resdfRsquaredMap) <- ntrees
  resdfMAEMap <- as.data.frame(resMAEMap)
  rownames(resdfMAEMap) <- mtrys
  colnames(resdfMAEMap) <- ntrees
  
  
  # convert dataframes to long format using tidyverse
  resdfRMSEMap <- resdfRMSEMap |>
                      rownames_to_column('mtry') |>
                          gather(key='ntree', value='RMSE', -mtry)
  
  resdfRsquaredMap <- resdfRsquaredMap |>
                          rownames_to_column('mtry') |>
                              gather(key='ntree', value='Rsquared', -mtry)
  
  resdfMAEMap <- resdfMAEMap |>
                    rownames_to_column('mtry') |>
                        gather(key='ntree', value='MAE', -mtry)
  
  # ensure ntree and mtry columns are ordered factors
  resdfRMSEMap$ntree <- factor(resdfRMSEMap$ntree, levels=as.character(ntrees))
  resdfRMSEMap$mtry <- factor(resdfRMSEMap$mtry, levels=as.character(mtrys))
  
  resdfRsquaredMap$ntree <- factor(resdfRsquaredMap$ntree, levels=as.character(ntrees))
  resdfRsquaredMap$mtry <- factor(resdfRsquaredMap$mtry, levels=as.character(mtrys))
  
  resdfMAEMap$ntree <- factor(resdfMAEMap$ntree, levels=as.character(ntrees))
  resdfMAEMap$mtry <- factor(resdfMAEMap$mtry, levels=as.character(mtrys))
  
  # plot heatmaps using ggplot, with extreme (min or max) value plotted as overlaid point using annotate and colourbar scale reversed
  pHeatmapRMSE <- ggplot(resdfRMSEMap) +
                    geom_tile(aes(x=ntree, y=mtry, fill=RMSE)) +
                        scale_fill_viridis(option="viridis", direction=-1) +
                          geom_point(data=resdfRMSEMap[which(resdfRMSEMap$RMSE
                                                             == min(resdfRMSEMap$RMSE),
                                                             arr.ind = TRUE),],
                                     aes(x=ntree, y=mtry), colour="red", size=2) +
                            guides(colour = guide_colourbar(reverse=TRUE)) +
                              labs(x="ntree", y="mtry", fill="RMSE") +
                                theme(text = element_text(family = "serif"))
  
  pHeatmapRsquared <- ggplot(resdfRsquaredMap) +
                        geom_tile(aes(x=ntree, y=mtry, fill=Rsquared)) +
                            scale_fill_viridis(option="viridis", direction=1) +
                              geom_point(data=resdfRsquaredMap[which(resdfRsquaredMap$Rsquared
                                                                     == max(resdfRsquaredMap$Rsquared),
                                                                     arr.ind = TRUE),],
                                         aes(x=ntree, y=mtry), colour="red", size=2) +
                                guides(colour = guide_colourbar(reverse=TRUE)) +
                                  labs(x="ntree", y="mtry", fill="Rsquared") +
                                    theme(text = element_text(family = "serif"))
  
  pHeatmapMAE <- ggplot(resdfMAEMap) +
                    geom_tile(aes(x=ntree, y=mtry, fill=MAE)) +
                        scale_fill_viridis(option="viridis", direction=-1) +
                          geom_point(data=resdfMAEMap[which(resdfMAEMap$MAE
                                                            == min(resdfMAEMap$MAE),
                                                            arr.ind = TRUE),],
                                     aes(x=ntree, y=mtry), colour="red", size=2) +
                            guides(colour = guide_colourbar(reverse=TRUE)) +
                              labs(x="ntree", y="mtry", fill="MAE") +
                                theme(text = element_text(family = "serif"))
  
  p <-  cowplot::plot_grid(pHeatmapRMSE,
                           pHeatmapRsquared,
                           pHeatmapMAE,
                           ncol=3, nrow=1)
  
  return(p)
  
}  # end of function

Part A analysis

Set global parameters


permImpCondThres <- 0.95
minsplit <- 20
minbucket <- 7
ntrees <- c(251, 501, 1001, 1501, 2501, 4001, 5501)

Mean change in annoyance

Initialise results output variables

resdAnnoyMnFit <- data.frame(RMSE = numeric(),
                             MAE = numeric(),
                             Rsquared = numeric())
resdAnnoyMnPermImp <- list()

All variables (absolute and difference)

Remove ambient only stimuli

Here, the ‘ambient only’ stimuli are removed, as the analysis cannot handle missing values for dB metrics.

stimDataANum <- stimDataANum[complete.cases(stimDataANum),]
stimDataANum$UASLAeq <- as.numeric(stimDataANum$UASLAeq)
stimDataANum$SNRlevel <- as.numeric(stimDataANum$SNRlevel)

Set variables


iVars <- names(stimDataANum)[which(names(stimDataANum) == 'UASLAeq'):which(names(stimDataANum) == 'UASImpulsSHM05ExMaxLR')]
iVars <- iVars[! iVars %in% 'SNRlevel']
iVars <- c(iVars,
           names(stimDataANum)[which(colnames(stimDataANum)=="LAeqLAF90diff"):
                               which(colnames(stimDataANum)=="dImpulsSHM05ExMaxLR")], "SNRlevel")
dVar <- "dAnnoyMean"

seeds <- c(14569, 98651, 54654498, 454948, 41321)

Hyperparameter tuning


p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
              ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

if (saveplots){
  ggsave(filename="PtAdAnnoyMnAllVarsHyperTune.svg", width=12, height=4, path=file.path(outFigPath, "svg"))
  unlink("PtAdAnnoyMnAllVarsHyperTune.svg")

  ggsave(filename="PtAdAnnoyMnAllVarsHyperTune.pdf", width=12, height=4, path=file.path(outFigPath, "pdf"))
  unlink("PtAdAnnoyMnAllVarsHyperTune.pdf")
}

Selected hyperparameters


ntree <- 251
mtry <- as.integer(length(iVars)/1.5)

Run model

Train preliminary model


nperm <- 10

resultsOutAbsDiffs <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutAbsDiffs$OOB_RMSE
[1] 0.434307
resultsOutAbsDiffs$OOB_MAE
[1] 0.3533671
resultsOutAbsDiffs$Rsquared
[1] 0.8738479

Train multiple seeds model


resultsOutAbsDiffs <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutAbsDiffs$OOB_RMSE
[1] 0.430126
resultsOutAbsDiffs$OOB_MAE
[1] 0.3537057
resultsOutAbsDiffs$Rsquared
[1] 0.875829
# store results
resdAnnoyMnFit['All vars', 'RMSE'] <- resultsOutAbsDiffs$OOB_RMSE
resdAnnoyMnFit['All vars', 'MAE'] <- resultsOutAbsDiffs$OOB_MAE
resdAnnoyMnFit['All vars', 'Rsquared'] <- resultsOutAbsDiffs$Rsquared
resdAnnoyMnPermImp$AllVars <- resultsOutAbsDiffs$conditional_permimp

Plot results

par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutAbsDiffs.conimp <- arrange(resultsOutAbsDiffs$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutAbsDiffs.conimp) + geom_col(aes(x=factor(rownames(resultsOutAbsDiffs.conimp), levels=rownames(resultsOutAbsDiffs.conimp)), y=CondPermImp), fill=mycolours[9], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (mean change in annoyance)") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtAdAnnoyMnAllVarsConPermimp.svg", width=8, height=20, path=file.path(outFigPath, "svg"))
  unlink("PtAdAnnoyMnAllVarsConPermimp.svg")

  ggsave(filename="PtAdAnnoyMnAllVarsConPermimp.pdf", width=8, height=20, path=file.path(outFigPath, "pdf"))
  unlink("PtAdAnnoyMnAllVarsConPermimp.pdf")
}

# Plot only positive values

resultsOutAbsDiffs.conimpPtv <- resultsOutAbsDiffs.conimp |>
                                          rownames_to_column('Metric') |>
                                                filter_if(is.numeric, all_vars(. > 0)) |>
                                                      column_to_rownames('Metric')

pBar <- ggplot(resultsOutAbsDiffs.conimpPtv) + geom_col(aes(x=factor(rownames(resultsOutAbsDiffs.conimpPtv), levels=rownames(resultsOutAbsDiffs.conimpPtv)), y=CondPermImp), fill=mycolours[9], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (mean change in annoyance)") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtAdAnnoyMnAllVarsConPermimpPtv.svg", width=8, height=8, path=file.path(outFigPath, "svg"))
  unlink("PtAdAnnoyMnAllVarsConPermimp.svg")
  
  ggsave(filename="PtAdAnnoyMnAllVarsConPermimpPtv.pdf", width=8, height=8, path=file.path(outFigPath, "pdf"))
  unlink("PtAdAnnoyMnAllVarsConPermimp.pdf")
}

Absolute variables

Set variables


iVars <- names(stimDataANum)[which(names(stimDataANum) == 'UASLAeq'):which(names(stimDataANum) == 'UASImpulsSHM05ExMaxLR')]
iVars <- iVars[! iVars %in% c('SNRlevel')]
dVar <- "dAnnoyMean"

seeds <- c(578312, 544, 84894, 54654, 153157)

Hyperparameter tuning


p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
              ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p


if (saveplots){
  ggsave(filename="PtAdAnnoyMnAbsVarsHyperTune.svg", width=12, height=4, path=file.path(outFigPath, "svg"))
  unlink("PtAdAnnoyMnAbsVarsHyperTune.svg")

  ggsave(filename="PtAdAnnoyMnAbsVarsHyperTune.pdf", width=12, height=4, path=file.path(outFigPath, "pdf"))
  unlink("PtAdAnnoyMnAbsVarsHyperTune.pdf")
}

Selected hyperparameters


ntree <- 1501
mtry <- as.integer(length(iVars)/1.25)

Run model

Train preliminary model


nperm <- 5

resultsOutAbs <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutAbs$OOB_RMSE
[1] 0.5920291
resultsOutAbs$OOB_MAE
[1] 0.4797379
resultsOutAbs$Rsquared
[1] 0.8046045

Train multiple seeds model


resultsOutAbs <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutAbs$OOB_RMSE
[1] 0.5898948
resultsOutAbs$OOB_MAE
[1] 0.4771605
resultsOutAbs$Rsquared
[1] 0.8064115

# store results
resdAnnoyMnFit['Abs vars', 'RMSE'] <- resultsOutAbs$OOB_RMSE
resdAnnoyMnFit['Abs vars', 'MAE'] <- resultsOutAbs$OOB_MAE
resdAnnoyMnFit['Abs vars', 'Rsquared'] <- resultsOutAbs$Rsquared
resdAnnoyMnPermImp$AbsVars <- resultsOutAbs$conditional_permimp

Plot results

par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutAbs.conimp <- arrange(resultsOutAbs$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutAbs.conimp) + geom_col(aes(x=factor(rownames(resultsOutAbs.conimp), levels=rownames(resultsOutAbs.conimp)), y=CondPermImp), fill=mycolours[1], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (mean change in annoyance)") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) +
  coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtAdAnnoyMnAbsVarsConPermimp.svg", width=8, height=11.5, path=file.path(outFigPath, "svg"))
  unlink("PtAdAnnoyMnAbsVarsConPermimp.svg")
  
  ggsave(filename="PtAdAnnoyMnAbsVarsConPermimp.pdf", width=8, height=11.5, path=file.path(outFigPath, "pdf"))
  unlink("PtAdAnnoyMnAbsVarsConPermimp.pdf")
}

# Plot values disregarding ambient LAeq

pBar <- ggplot(slice(resultsOutAbs.conimp, 1:n()-1)) + geom_col(aes(x=factor(rownames(slice(resultsOutAbs.conimp, 1:n()-1)), levels=rownames(slice(resultsOutAbs.conimp, 1:n()-1))), y=CondPermImp), fill=mycolours[1], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (mean change in annoyance)") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtAdAnnoyMnAbsVarsSkipAmbConPermimp.svg", width=8, height=11.5, path=file.path(outFigPath, "svg"))
  unlink("PtAdAnnoyMnAbsVarsSkipAmbConPermimp.svg")
  
  ggsave(filename="PtAdAnnoyMnAbsVarsSkipAmbConPermimp.pdf", width=8, height=11.5, path=file.path(outFigPath, "pdf"))
  unlink("PtAdAnnoyMnAbsVarsSkipAmbConPermimp.pdf")
}

# Plot only positive values disregarding ambient LAeq

resultsOutAbs.conimpPtv <- resultsOutAbs.conimp |>
                                          rownames_to_column('Metric') |>
                                                filter_if(is.numeric, all_vars(. > 0)) |>
                                                      column_to_rownames('Metric')

pBar <- ggplot(slice(resultsOutAbs.conimpPtv, 1:n()-1)) + geom_col(aes(x=factor(rownames(slice(resultsOutAbs.conimpPtv, 1:n()-1)), levels=rownames(slice(resultsOutAbs.conimpPtv, 1:n()-1))), y=CondPermImp), fill=mycolours[1], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (mean change in annoyance)") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtAdAnnoyMnAbsVarsSkipAmbConPermimpPtv.svg", width=8, height=7, path=file.path(outFigPath, "svg"))
  unlink("PtAdAnnoyMnAbsVarsSkipAmbConPermimpPtv.svg")
  
  ggsave(filename="PtAdAnnoyMnAbsVarsSkipAmbConPermimpPtv.pdf", width=8, height=7, path=file.path(outFigPath, "pdf"))
  unlink("PtAdAnnoyMnAbsVarsSkipAmbConPermimpPtv.pdf")
}

Selected metric


absVar <- "UASLoudECMAPowAvgBin"

SQM analysis

Replace ambient only stimuli

Here, the ‘ambient only’ stimuli are replaced, as the SQM analysis can incorporate 0 values (whereas dB metrics cannot be handled in this way).


stimDataANum <- rbind(stimDataANum, stimDataA[stimDataA['Stimulus']
                                              == "A1",
                                              colnames(stimDataANum)],
                      stimDataA[stimDataA['Stimulus']
                                              == "A2",
                                              colnames(stimDataANum)])
stimDataANum <- arrange(stimDataANum, Stimulus)

Individual SQMs

Sharpness
Set variables

iVars <- c(absVar, "AmbientLAeq", "UASSharpAurISO3PowAvgMaxLR", "UASSharpAurISO305ExMaxLR", "UASSharpAurSHMPowAvgMaxLR", "UASSharpAurSHM05ExMaxLR", "UASSharpAurISO1PowAvgMaxLR", "UASSharpAurISO105ExMaxLR", "UASSharpvBISO1PowAvgMaxLR", "UASSharpvBISO105ExMaxLR", "UASSharpDINPowAvgMaxLR", "UASSharpDIN05ExMaxLR")
dVar <- "dAnnoyMean"

seeds <- c(7041, 905, 4984651, 6513213, 120651)
Hyperparameter tuning

p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 251
mtry <- as.integer(length(iVars)/1.5)
Run model

Train preliminary model


nperm <- 5

resultsOutSharp <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutSharp$OOB_RMSE
[1] 0.6033145
resultsOutSharp$OOB_MAE
[1] 0.4893915
resultsOutSharp$Rsquared
[1] 0.8146039

Train multiple seeds model


resultsOutSharp <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutSharp$OOB_RMSE
[1] 0.5917107
resultsOutSharp$OOB_MAE
[1] 0.4752747
resultsOutSharp$Rsquared
[1] 0.8242231
# store results
resdAnnoyMnFit['Abs sharp', 'RMSE'] <- resultsOutSharp$OOB_RMSE
resdAnnoyMnFit['Abs sharp', 'MAE'] <- resultsOutSharp$OOB_MAE
resdAnnoyMnFit['Abs sharp', 'Rsquared'] <- resultsOutSharp$Rsquared
resdAnnoyMnPermImp$AbsSharp <- resultsOutSharp$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutSharp.conimp <- arrange(resultsOutSharp$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutSharp.conimp) + geom_col(aes(x=factor(rownames(resultsOutSharp.conimp), levels=rownames(resultsOutSharp.conimp)), y=CondPermImp), fill=mycolours[2], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (mean change in annoyance)") + ggtitle("Sharpness") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtAdAnnoyMnSharpConPermimp.svg", width=8, height=4.9, path=file.path(outFigPath, "svg"))
  unlink("PtAdAnnoyMnSharpConPermimp.svg")
  
  ggsave(filename="PtAdAnnoyMnSharpConPermimp.pdf", width=8, height=4.9, path=file.path(outFigPath, "pdf"))
  unlink("PtAdAnnoyMnSharpConPermimp.pdf")
}

Selected metric


sharpVar <- "UASSharpAurISO305ExMaxLR"
Tonal loudness and tonality
Set variables

iVars <- c(absVar, "AmbientLAeq", "UASTonalECMAAvgMaxLR", "UASTonalSHMInt05ExMaxLR", "UASTonalSHMIntAvgMaxLR", "UASTonalECMA05ExMaxLR", "UASTonLdECMAPowAvgBin", "UASTonLdECMA05ExBin", "UASTonalAurAvgMaxLR", "UASTonalAur05ExMaxLR", "UASTonalAur10ExMaxLR")
dVar <- "dAnnoyMean"

seeds <- c(540, 104798, 456464, 87331, 94564)
Hyperparameter tuning

p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 1001
mtry <- as.integer(length(iVars)/1.5)
Run model

Train preliminary model

# Tonality with tonal loudness

nperm <- 5

resultsOutTonal1 <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutTonal1$OOB_RMSE
[1] 0.6390897
resultsOutTonal1$OOB_MAE
[1] 0.5098136
resultsOutTonal1$Rsquared
[1] 0.7782498

Train multiple seeds model

# Tonality with tonal loudness

resultsOutTonal1 <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutTonal1$OOB_RMSE
[1] 0.6330849
resultsOutTonal1$OOB_MAE
[1] 0.5045541
resultsOutTonal1$Rsquared
[1] 0.7848499
# store results
resdAnnoyMnFit['Abs tonal inc loud', 'RMSE'] <- resultsOutTonal1$OOB_RMSE
resdAnnoyMnFit['Abs tonal inc loud', 'MAE'] <- resultsOutTonal1$OOB_MAE
resdAnnoyMnFit['Abs tonal inc loud', 'Rsquared'] <- resultsOutTonal1$Rsquared
resdAnnoyMnPermImp$AbsTonal1 <- resultsOutTonal1$conditional_permimp
Plot results

par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutTonal1.conimp <- arrange(resultsOutTonal1$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutTonal1.conimp) + geom_col(aes(x=factor(rownames(resultsOutTonal1.conimp), levels=rownames(resultsOutTonal1.conimp)), y=CondPermImp), fill=mycolours[3], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (mean change in annoyance)") + ggtitle("Tonality inc. tonal loudness") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip(ylim=c(0, 1.2))
pBar


if (saveplots){
  ggsave(filename="PtAdAnnoyMnTonalLdConPermimp.svg", width=8, height=3.8, path=file.path(outFigPath, "svg"))
  unlink("PtAdAnnoyMnTonalLdConPermimp.svg")
  
  ggsave(filename="PtAdAnnoyMnTonalLdConPermimp.pdf", width=8, height=3.8, path=file.path(outFigPath, "pdf"))
  unlink("PtAdAnnoyMnTonalLdConPermimp.pdf")
}

Selected metric


tonLdVar <- "UASTonLdECMAPowAvgBin"
Tonality without tonal loudness
Set variables

iVars <- c(absVar, "AmbientLAeq", "UASTonalECMAAvgMaxLR", "UASTonalSHMInt05ExMaxLR", "UASTonalSHMIntAvgMaxLR", "UASTonalECMA05ExMaxLR", "UASTonalAurAvgMaxLR", "UASTonalAur05ExMaxLR", "UASTonalAur10ExMaxLR")
dVar <- "dAnnoyMean"

seeds <- c(156089, 5860, 10528, 89541, 4685146)
Hyperparameter tuning

p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 1001
mtry <- as.integer(length(iVars)/1.5)
Run model

Train preliminary model

# Tonality

nperm <- 5

resultsOutTonal2 <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutTonal2$OOB_RMSE
[1] 0.6030948
resultsOutTonal2$OOB_MAE
[1] 0.4825113
resultsOutTonal2$Rsquared
[1] 0.8186149

Train multiple seeds model

# Tonality

resultsOutTonal2 <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutTonal2$OOB_RMSE
[1] 0.6032431
resultsOutTonal2$OOB_MAE
[1] 0.4815779
resultsOutTonal2$Rsquared
[1] 0.8154112

# store results
resdAnnoyMnFit['Abs tonal no loud', 'RMSE'] <- resultsOutTonal2$OOB_RMSE
resdAnnoyMnFit['Abs tonal no loud', 'MAE'] <- resultsOutTonal2$OOB_MAE
resdAnnoyMnFit['Abs tonal no loud', 'Rsquared'] <- resultsOutTonal2$Rsquared
resdAnnoyMnPermImp$AbsTonal2 <- resultsOutTonal2$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutTonal2.conimp <- arrange(resultsOutTonal2$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutTonal2.conimp) + geom_col(aes(x=factor(rownames(resultsOutTonal2.conimp), levels=rownames(resultsOutTonal2.conimp)), y=CondPermImp), fill=mycolours[3], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (mean change in annoyance)") + ggtitle("Tonality w/o tonal loudness") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip(ylim=c(0, 1.2))
pBar


if (saveplots){
  ggsave(filename="PtAdAnnoyMnTonalConPermimp.svg", width=8, height=3.2, path=file.path(outFigPath, "svg"))
  unlink("PtAdAnnoyMnTonalConPermimp.svg")
  
  ggsave(filename="PtAdAnnoyMnTonalConPermimp.pdf", width=8, height=3.2, path=file.path(outFigPath, "pdf"))
  unlink("PtAdAnnoyMnTonalConPermimp.pdf")
}

Selected metric


tonalVar <- "UASTonalSHMInt05ExMaxLR"
Fluctuation strength
Set variables

# Fluctuation strength
iVars <- c(absVar, "AmbientLAeq", "UASFluctSHM10ExBin", "UASFluctSHM05ExBin", "UASFluctFZ10ExMaxLR", "UASFluctFZ05ExMaxLR", "UASFluctOV10ExMaxLR", "UASFluctOV05ExMaxLR")
dVar <- "dAnnoyMean"

seeds <- c(25107, 546098, 195, 5937, 102658)
Hyperparameter tuning

p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 5501
mtry <- as.integer(length(iVars)/1.25)
Run model

Train preliminary model


nperm <- 5

resultsOutFluct <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutFluct$OOB_RMSE
[1] 0.5843817
resultsOutFluct$OOB_MAE
[1] 0.4552687
resultsOutFluct$Rsquared
[1] 0.8202794

Train multiple seeds model


resultsOutFluct <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutFluct$OOB_RMSE
[1] 0.5847776
resultsOutFluct$OOB_MAE
[1] 0.456084
resultsOutFluct$Rsquared
[1] 0.8194579

# store results
resdAnnoyMnFit['Abs fluct', 'RMSE'] <- resultsOutFluct$OOB_RMSE
resdAnnoyMnFit['Abs fluct', 'MAE'] <- resultsOutFluct$OOB_MAE
resdAnnoyMnFit['Abs fluct', 'Rsquared'] <- resultsOutFluct$Rsquared
resdAnnoyMnPermImp$AbsFluct <- resultsOutFluct$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutFluct.conimp <- arrange(resultsOutFluct$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutFluct.conimp) + geom_col(aes(x=factor(rownames(resultsOutFluct.conimp), levels=rownames(resultsOutFluct.conimp)), y=CondPermImp), fill=mycolours[4], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (mean change in annoyance)") + ggtitle("Fluctuation strength") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtAdAnnoyMnFluctConPermimp.svg", width=8, height=2.9, path=file.path(outFigPath, "svg"))
  unlink("PtAdAnnoyMnFluctConPermimp.svg")
  
  ggsave(filename="PtAdAnnoyMnFluctConPermimp.pdf", width=8, height=2.9, path=file.path(outFigPath, "pdf"))
  unlink("PtAdAnnoyMnFluctConPermimp.pdf")
}

Selected metric


fluctVar <- "UASFluctOV10ExMaxLR"
Roughness
Set variables

# Roughness
iVars <- c(absVar, "AmbientLAeq", "UASRoughECMA10ExBin", "UASRoughECMA05ExBin", "UASRoughFZ10ExMaxLR", "UASRoughFZ05ExMaxLR", "UASRoughDW10ExMaxLR", "UASRoughDW05ExMaxLR")
dVar <- "dAnnoyMean"

seeds <- c(4701, 52187, 16589, 65217, 16893)
Hyperparameter tuning

p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 2501
mtry <- as.integer(length(iVars)/1.25)
Run model

Train preliminary model


nperm <- 5

resultsOutRough <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutRough$OOB_RMSE
[1] 0.5978974
resultsOutRough$OOB_MAE
[1] 0.465474
resultsOutRough$Rsquared
[1] 0.8040179

Train multiple seeds model


resultsOutRough <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutRough$OOB_RMSE
[1] 0.5997308
resultsOutRough$OOB_MAE
[1] 0.4671883
resultsOutRough$Rsquared
[1] 0.8028445
# store results
resdAnnoyMnFit['Abs rough', 'RMSE'] <- resultsOutRough$OOB_RMSE
resdAnnoyMnFit['Abs rough', 'MAE'] <- resultsOutRough$OOB_MAE
resdAnnoyMnFit['Abs rough', 'Rsquared'] <- resultsOutRough$Rsquared
resdAnnoyMnPermImp$AbsRough <- resultsOutRough$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutRough.conimp <- arrange(resultsOutRough$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutRough.conimp) + geom_col(aes(x=factor(rownames(resultsOutRough.conimp), levels=rownames(resultsOutRough.conimp)), y=CondPermImp), fill=mycolours[5], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (mean change in annoyance)") + ggtitle("Roughness") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtAdAnnoyMnRoughConPermimp.svg", width=8, height=2.9, path=file.path(outFigPath, "svg"))
  unlink("PtAdAnnoyMnRoughConPermimp.svg")
  
  ggsave(filename="PtAdAnnoyMnRoughConPermimp.pdf", width=8, height=2.9, path=file.path(outFigPath, "pdf"))
  unlink("PtAdAnnoyMnRoughConPermimp.pdf")
}

Selected metric


roughVar <- "UASRoughFZ05ExMaxLR"
Impulsiveness
Set variables
# Impulsiveness
iVars <- c(absVar, "AmbientLAeq", "UASImpulsSHMAvgMaxLR", "UASImpulsSHM05ExMaxLR", "UASImpulsSHMPowAvgMaxLR")
dVar <- "dAnnoyMean"

seeds <- c(8495, 59867, 5416, 9843, 86)
Hyperparameter tuning

p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 251
mtry <- as.integer(length(iVars)/1.25)
Run model

Train preliminary model


nperm <- 5

resultsOutImpuls <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutImpuls$OOB_RMSE
[1] 0.6105395
resultsOutImpuls$OOB_MAE
[1] 0.4733032
resultsOutImpuls$Rsquared
[1] 0.7863911

Train multiple seeds model


resultsOutImpuls <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutImpuls$OOB_RMSE
[1] 0.603079
resultsOutImpuls$OOB_MAE
[1] 0.4665693
resultsOutImpuls$Rsquared
[1] 0.7960339

# store results
resdAnnoyMnFit['Abs impuls', 'RMSE'] <- resultsOutImpuls$OOB_RMSE
resdAnnoyMnFit['Abs impuls', 'MAE'] <- resultsOutImpuls$OOB_MAE
resdAnnoyMnFit['Abs impuls', 'Rsquared'] <- resultsOutImpuls$Rsquared
resdAnnoyMnPermImp$AbsImpuls <- resultsOutImpuls$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutImpuls.conimp <- arrange(resultsOutImpuls$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutImpuls.conimp) + geom_col(aes(x=factor(rownames(resultsOutImpuls.conimp), levels=rownames(resultsOutImpuls.conimp)), y=CondPermImp), fill=mycolours[6], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (mean change in annoyance)") + ggtitle("Impulsiveness") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtAdAnnoyMnImpulsConPermimp.svg", width=8, height=2, path=file.path(outFigPath, "svg"))
  unlink("PtAdAnnoyMnImpulsConPermimp.svg")
  
  ggsave(filename="PtAdAnnoyMnImpulsConPermimp.pdf", width=8, height=2, path=file.path(outFigPath, "pdf"))
  unlink("PtAdAnnoyMnImpulsConPermimp.pdf")
}

Selected metric


impulsVar <- "UASImpulsSHMAvgMaxLR"

SQM and loudness comparison

Now the highest importance SQMs are ranked against each other, controlling for UAS loudness and ambient LAeq.

Include tonal loudness
Set variables

iVars <- c(absVar, "AmbientLAeq", sharpVar, tonLdVar, fluctVar, roughVar, impulsVar)
dVar <- "dAnnoyMean"

seeds <- c(70498, 4, 14986, 453, 864)
Hyperparameter tuning

p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 1001
mtry <- as.integer(length(iVars)/1.25)
Run model

Train preliminary model


nperm <- 5

resultsOutSQMs1 <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutSQMs1$OOB_RMSE
[1] 0.6099365
resultsOutSQMs1$OOB_MAE
[1] 0.4869588
resultsOutSQMs1$Rsquared
[1] 0.8025851

Train multiple seeds model


resultsOutSQMs1 <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutSQMs1$OOB_RMSE
[1] 0.60767
resultsOutSQMs1$OOB_MAE
[1] 0.4855243
resultsOutSQMs1$Rsquared
[1] 0.805056

# store results
resdAnnoyMnFit['Abs SQMs inc tonal loud', 'RMSE'] <- resultsOutSQMs1$OOB_RMSE
resdAnnoyMnFit['Abs SQMs inc tonal loud', 'MAE'] <- resultsOutSQMs1$OOB_MAE
resdAnnoyMnFit['Abs SQMs inc tonal loud', 'Rsquared'] <- resultsOutSQMs1$Rsquared
resdAnnoyMnPermImp$AbsSQMs1 <- resultsOutSQMs1$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutSQMs1.conimp <- arrange(resultsOutSQMs1$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutSQMs1.conimp) + geom_col(aes(x=factor(rownames(resultsOutSQMs1.conimp), levels=rownames(resultsOutSQMs1.conimp)), y=CondPermImp), fill=mycolours[7], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (mean change in annoyance)") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip(ylim=c(0, 1))
pBar


if (saveplots){
  ggsave(filename="PtAdAnnoyMnAbsSQMsTonLdConPermimp.svg", width=8, height=2.4, path=file.path(outFigPath, "svg"))
  unlink("PtAdAnnoyMnAbsSQMsTonLdConPermimp.svg")
  
  ggsave(filename="PtAdAnnoyMnAbsSQMsTonLdConPermimp.pdf", width=8, height=2.4, path=file.path(outFigPath, "pdf"))
  unlink("PtAdAnnoyMnAbsSQMsTonLdConPermimp.pdf")
}
Exclude tonal loudness
Set variables

iVars <- c(absVar, "AmbientLAeq", sharpVar, tonalVar, fluctVar, roughVar, impulsVar)
dVar <- "dAnnoyMean"

seeds <- c(546, 57203, 270835, 60592, 8094)
Hyperparameter tuning

p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 4001
mtry <- as.integer(length(iVars)/1.25)
Run model

Train preliminary model


nperm <- 5

resultsOutSQMs2 <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutSQMs2$OOB_RMSE
[1] 0.5870765
resultsOutSQMs2$OOB_MAE
[1] 0.4689816
resultsOutSQMs2$Rsquared
[1] 0.8254522

Train multiple seeds model


resultsOutSQMs2 <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutSQMs2$OOB_RMSE
[1] 0.5880773
resultsOutSQMs2$OOB_MAE
[1] 0.469515
resultsOutSQMs2$Rsquared
[1] 0.8255209

# store results
resdAnnoyMnFit['Abs SQMs no tonal loud', 'RMSE'] <- resultsOutSQMs2$OOB_RMSE
resdAnnoyMnFit['Abs SQMs no tonal loud', 'RMSE'] <- resultsOutSQMs2$OOB_MAE
resdAnnoyMnFit['Abs SQMs no tonal loud', 'Rsquared'] <- resultsOutSQMs2$Rsquared
resdAnnoyMnPermImp$AbsSQMs2 <- resultsOutSQMs2$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutSQMs2.conimp <- arrange(resultsOutSQMs2$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutSQMs2.conimp) + geom_col(aes(x=factor(rownames(resultsOutSQMs2.conimp), levels=rownames(resultsOutSQMs2.conimp)), y=CondPermImp), fill=mycolours[7], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (mean change in annoyance)") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip(ylim=c(0, 1))
pBar


if (saveplots){
  ggsave(filename="PtAdAnnoyMnAbsSQMsNoTonLdConPermimp.svg", width=8, height=2.4, path=file.path(outFigPath, "svg"))
  unlink("PtAdAnnoyMnAbsSQMsNoTonLdConPermimp.svg")
  
  ggsave(filename="PtAdAnnoyMnAbsSQMsNoTonLdConPermimp.pdf", width=8, height=2.4, path=file.path(outFigPath, "pdf"))
  unlink("PtAdAnnoyMnAbsSQMsNoTonLdConPermimp.pdf")
}

Difference variables

Next, the difference metrics are analysed,

Remove ambient only stimuli

Here, the ‘ambient only’ stimuli are removed, as the analysis cannot handle missing values for dB metrics.

stimDataANum <- stimDataANum[complete.cases(stimDataANum),]
stimDataANum$UASLAeq <- as.numeric(stimDataANum$UASLAeq)
stimDataANum$SNRlevel <- as.numeric(stimDataANum$SNRlevel)

Set variables


iVars <- c(names(stimDataANum)[which(colnames(stimDataANum)=="LAeqLAF90diff"):
                               which(colnames(stimDataANum)=="dImpulsSHM05ExMaxLR")], "SNRlevel")
dVar <- "dAnnoyMean"

seeds <- c(568392, 498, 4089, 78132, 741809)

Hyperparameter tuning


p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 251
mtry <- as.integer(length(iVars)/1.25)

Run model

Train preliminary model


nperm <- 5

resultsOutDiffs <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutDiffs$OOB_RMSE
[1] 0.4308342
resultsOutDiffs$OOB_MAE
[1] 0.3567504
resultsOutDiffs$Rsquared
[1] 0.8740203

Train multiple seeds model


resultsOutDiffs <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutDiffs$OOB_RMSE
[1] 0.4314902
resultsOutDiffs$OOB_MAE
[1] 0.3566699
resultsOutDiffs$Rsquared
[1] 0.8741682

# store results
resdAnnoyMnFit['Diff vars', 'RMSE'] <- resultsOutDiffs$OOB_RMSE
resdAnnoyMnFit['Diff vars', 'MAE'] <- resultsOutDiffs$OOB_MAE
resdAnnoyMnFit['Diff vars', 'Rsquared'] <- resultsOutDiffs$Rsquared
resdAnnoyMnPermImp$DiffVars <- resultsOutDiffs$conditional_permimp

Plot results

par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutDiffs.conimp <- arrange(resultsOutDiffs$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutDiffs.conimp) + geom_col(aes(x=factor(rownames(resultsOutDiffs.conimp), levels=rownames(resultsOutDiffs.conimp)), y=CondPermImp), fill=mycolours[8], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (mean change in annoyance)") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtAdAnnoyMnDiffVarsConPermimp.svg", width=8, height=10, path=file.path(outFigPath, "svg"))
  unlink("PtAdAnnoyMnDiffVarsConPermimp.svg")
  
  ggsave(filename="PtAdAnnoyMnDiffVarsConPermimp.pdf", width=8, height=10, path=file.path(outFigPath, "pdf"))
  unlink("PtAdAnnoyMnDiffVarsConPermimp.pdf")
}

# Plot only positive values
resultsOutDiffs.conimpPtv <- resultsOutDiffs.conimp |>
                                        rownames_to_column('Metric') |>
                                            filter_if(is.numeric, all_vars(. > 0)) |>
                                                  column_to_rownames('Metric')

pBar <- ggplot(resultsOutDiffs.conimpPtv) + geom_col(aes(x=factor(rownames(resultsOutDiffs.conimpPtv), levels=rownames(resultsOutDiffs.conimpPtv)), y=CondPermImp), fill=mycolours[8], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (mean change in annoyance)") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtAdAnnoyMnDiffVarsConPermimpPtv.svg", width=8, height=8, path=file.path(outFigPath, "svg"))
  unlink("PtAdAnnoyMnDiffVarsConPermimpPtv.svg")
  
  ggsave(filename="PtAdAnnoyMnDiffVarsConPermimpPtv.pdf", width=8, height=8, path=file.path(outFigPath, "pdf"))
  unlink("PtAdAnnoyMnDiffVarsConPermimpPtv.pdf")
}

Selected metric


diffVar <- "EPNLLAF50diff"

dSQM analysis

The ambient-only stimuli are NOT replaced here, as the difference analysis includes dB metrics.

Individual SQMs

dSharpness
Set variables

iVars <- c(diffVar, "dSharpAurISO3PowAvgMaxLR", "dSharpAurISO305ExMaxLR", "dSharpAurSHMPowAvgMaxLR", "dSharpAurSHM05ExMaxLR")
dVar <- "dAnnoyMean"

seeds <- c(84194, 905, 64815, 928054, 625091)
Hyperparameter tuning

p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 2501
mtry <- as.integer(length(iVars)/1.25)
Run model

Train preliminary model


nperm <- 5

resultsOutSharp <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutSharp$OOB_RMSE
[1] 0.4523884
resultsOutSharp$OOB_MAE
[1] 0.3595752
resultsOutSharp$Rsquared
[1] 0.8627182

Train multiple seeds model


resultsOutSharp <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutSharp$OOB_RMSE
[1] 0.4536154
resultsOutSharp$OOB_MAE
[1] 0.3606428
resultsOutSharp$Rsquared
[1] 0.8618904
# store results
resdAnnoyMnFit['Diff sharp', 'RMSE'] <- resultsOutSharp$OOB_RMSE
resdAnnoyMnFit['Diff sharp', 'MAE'] <- resultsOutSharp$OOB_MAE
resdAnnoyMnFit['Diff sharp', 'Rsquared'] <- resultsOutSharp$Rsquared
resdAnnoyMnPermImp$DiffSharp <- resultsOutSharp$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutSharp.conimp <- arrange(resultsOutSharp$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutSharp.conimp) + geom_col(aes(x=factor(rownames(resultsOutSharp.conimp), levels=rownames(resultsOutSharp.conimp)), y=CondPermImp), fill=mycolours[2], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (mean change in annoyance)") + ggtitle("dSharpness") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtAdAnnoyMndSharpConPermimp.svg", width=8, height=2.6, path=file.path(outFigPath, "svg"))
  unlink("PtAdAnnoyMndSharpConPermimp.svg")
  
  ggsave(filename="PtAdAnnoyMndSharpConPermimp.pdf", width=8, height=2.6, path=file.path(outFigPath, "pdf"))
  unlink("PtAdAnnoyMndSharpConPermimp.pdf")
}

Selected metric


dSharpVar <- "dSharpAurISO3PowAvgMaxLR"
dTonal loudness and dtonality
Set variables

iVars <- c(diffVar, "dTonalECMAAvgMaxLR", "dTonalSHMInt05ExMaxLR", "dTonalSHMIntAvgMaxLR", "dTonalECMA05ExMaxLR", "dTonLdECMAPowAvgBin", "dTonLdECMA05ExBin")
dVar <- "dAnnoyMean"

seeds <- c(561684, 104798, 1536, 48, 48561)
Hyperparameter tuning

p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 1501
mtry <- as.integer(length(iVars)/1.25)
Run model

Train preliminary model

# Tonality with tonal loudness

nperm <- 5

resultsOutTonal1 <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutTonal1$OOB_RMSE
[1] 0.4541254
resultsOutTonal1$OOB_MAE
[1] 0.3676218
resultsOutTonal1$Rsquared
[1] 0.8616272

Train multiple seeds model

# Tonality with tonal loudness

resultsOutTonal1 <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutTonal1$OOB_RMSE
[1] 0.4527969
resultsOutTonal1$OOB_MAE
[1] 0.3685465
resultsOutTonal1$Rsquared
[1] 0.8625633
# store results
resdAnnoyMnFit['Diff tonal inc loud', 'RMSE'] <- resultsOutTonal1$OOB_RMSE
resdAnnoyMnFit['Diff tonal inc loud', 'MAE'] <- resultsOutTonal1$OOB_MAE
resdAnnoyMnFit['Diff tonal inc loud', 'Rsquared'] <- resultsOutTonal1$Rsquared
resdAnnoyMnPermImp$DiffTonal1 <- resultsOutTonal1$conditional_permimp
Plot results

par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutTonal1.conimp <- arrange(resultsOutTonal1$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutTonal1.conimp) + geom_col(aes(x=factor(rownames(resultsOutTonal1.conimp), levels=rownames(resultsOutTonal1.conimp)), y=CondPermImp), fill=mycolours[3], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (mean change in annoyance)") + ggtitle("dTonality inc. dtonal loudness") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip(ylim=c(0, 1.6))
pBar


if (saveplots){
  ggsave(filename="PtAdAnnoyMndTonalLdConPermimp.svg", width=8, height=2.6, path=file.path(outFigPath, "svg"))
  unlink("PtAdAnnoyMndTonalLdConPermimp.svg")
  
  ggsave(filename="PtAdAnnoyMndTonalLdConPermimp.pdf", width=8, height=2.6, path=file.path(outFigPath, "pdf"))
  unlink("PtAdAnnoyMndTonalLdConPermimp.pdf")
}

Selected metric


dTonLdVar <- "dTonLdECMAPowAvgBin"
dTonality without dtonal loudness
Set variables

iVars <- c(diffVar, "dTonalECMAAvgMaxLR", "dTonalSHMInt05ExMaxLR", "dTonalSHMIntAvgMaxLR", "dTonalECMA05ExMaxLR")
dVar <- "dAnnoyMean"

seeds <- c(410865, 2954, 70812, 203, 7984)
Hyperparameter tuning

p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 4001
mtry <- as.integer(length(iVars)/1.25)
Run model

Train preliminary model

# Tonality

nperm <- 5

resultsOutTonal2 <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutTonal2$OOB_RMSE
[1] 0.462319
resultsOutTonal2$OOB_MAE
[1] 0.3667896
resultsOutTonal2$Rsquared
[1] 0.8545831

Train multiple seeds model

# Tonality

resultsOutTonal2 <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutTonal2$OOB_RMSE
[1] 0.4619735
resultsOutTonal2$OOB_MAE
[1] 0.3664541
resultsOutTonal2$Rsquared
[1] 0.8548939

# store results
resdAnnoyMnFit['Diff tonal no loud', 'RMSE'] <- resultsOutTonal2$OOB_RMSE
resdAnnoyMnFit['Diff tonal no loud', 'MAE'] <- resultsOutTonal2$OOB_MAE
resdAnnoyMnFit['Diff tonal no loud', 'Rsquared'] <- resultsOutTonal2$Rsquared
resdAnnoyMnPermImp$DiffTonal2 <- resultsOutTonal2$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutTonal2.conimp <- arrange(resultsOutTonal2$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutTonal2.conimp) + geom_col(aes(x=factor(rownames(resultsOutTonal2.conimp), levels=rownames(resultsOutTonal2.conimp)), y=CondPermImp), fill=mycolours[3], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (mean change in annoyance)") + ggtitle("dTonality w/o tonal loudness") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip(ylim=c(0, 1.6))
pBar


if (saveplots){
  ggsave(filename="PtAdAnnoyMndTonalConPermimp.svg", width=8, height=2, path=file.path(outFigPath, "svg"))
  unlink("PtAdAnnoyMndTonalConPermimp.svg")
  
  ggsave(filename="PtAdAnnoyMndTonalConPermimp.pdf", width=8, height=2, path=file.path(outFigPath, "pdf"))
  unlink("PtAdAnnoyMndTonalConPermimp.pdf")
}

Selectec metric


dTonalVar <- "dTonalSHMIntAvgMaxLR"
dFluctuation strength
Set variables

# Fluctuation strength
iVars <- c(diffVar, "dFluctSHM10ExBin", "dFluctSHM05ExBin", "dFluctOV10ExMaxLR", "dFluctOV05ExMaxLR")
dVar <- "dAnnoyMean"

seeds <- c(418657, 84, 1630, 18659, 3687)
Hyperparameter tuning

p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 1001
mtry <- as.integer(length(iVars)/1.25)
Run model

Train preliminary model


nperm <- 5

resultsOutFluct <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutFluct$OOB_RMSE
[1] 0.4693879
resultsOutFluct$OOB_MAE
[1] 0.3674453
resultsOutFluct$Rsquared
[1] 0.8512241

Train multiple seeds model


resultsOutFluct <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutFluct$OOB_RMSE
[1] 0.4696581
resultsOutFluct$OOB_MAE
[1] 0.368869
resultsOutFluct$Rsquared
[1] 0.8511147

# store results
resdAnnoyMnFit['Diff fluct', 'RMSE'] <- resultsOutFluct$OOB_RMSE
resdAnnoyMnFit['Diff fluct', 'MAE'] <- resultsOutFluct$OOB_MAE
resdAnnoyMnFit['Diff fluct', 'Rsquared'] <- resultsOutFluct$Rsquared
resdAnnoyMnPermImp$DiffFluct <- resultsOutFluct$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutFluct.conimp <- arrange(resultsOutFluct$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutFluct.conimp) + geom_col(aes(x=factor(rownames(resultsOutFluct.conimp), levels=rownames(resultsOutFluct.conimp)), y=CondPermImp), fill=mycolours[4], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (mean change in annoyance)") + ggtitle("dFluctuation strength") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtAdAnnoyMndFluctConPermimp.svg", width=8, height=2, path=file.path(outFigPath, "svg"))
  unlink("PtAdAnnoyMnFluctConPermimp.svg")
  
  ggsave(filename="PtAdAnnoyMndFluctConPermimp.pdf", width=8, height=2, path=file.path(outFigPath, "pdf"))
  unlink("PtAdAnnoyMnFluctConPermimp.pdf")
}

Selected metric


dFluctVar <- "dFluctOV10ExMaxLR"
dRoughness
Set variables

# Roughness
iVars <- c(diffVar, "dRoughECMA10ExBin", "dRoughECMA05ExBin", "dRoughFZ10ExMaxLR", "dRoughFZ05ExMaxLR")
dVar <- "dAnnoyMean"

seeds <- c(69851, 85109, 410986, 1563, 896)
Hyperparameter tuning

p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 1501
mtry <- as.integer(length(iVars)/1.25)
Run model

Train preliminary model


nperm <- 5

resultsOutRough <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutRough$OOB_RMSE
[1] 0.4931997
resultsOutRough$OOB_MAE
[1] 0.372368
resultsOutRough$Rsquared
[1] 0.839582

Train multiple seeds model


resultsOutRough <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutRough$OOB_RMSE
[1] 0.4955747
resultsOutRough$OOB_MAE
[1] 0.3727289
resultsOutRough$Rsquared
[1] 0.8381762
# store results
resdAnnoyMnFit['Diff rough', 'RMSE'] <- resultsOutRough$OOB_RMSE
resdAnnoyMnFit['Diff rough', 'MAE'] <- resultsOutRough$OOB_MAE
resdAnnoyMnFit['Diff rough', 'Rsquared'] <- resultsOutRough$Rsquared
resdAnnoyMnPermImp$DiffRough <- resultsOutRough$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutRough.conimp <- arrange(resultsOutRough$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutRough.conimp) + geom_col(aes(x=factor(rownames(resultsOutRough.conimp), levels=rownames(resultsOutRough.conimp)), y=CondPermImp), fill=mycolours[5], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (mean change in annoyance)") + ggtitle("dRoughness") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtAdAnnoyMndRoughConPermimp.svg", width=8, height=2, path=file.path(outFigPath, "svg"))
  unlink("PtAdAnnoyMndRoughConPermimp.svg")
  
  ggsave(filename="PtAdAnnoyMndRoughConPermimp.pdf", width=8, height=2, path=file.path(outFigPath, "pdf"))
  unlink("PtAdAnnoyMndRoughConPermimp.pdf")
}

Selected metric


dRoughVar <- "dRoughECMA05ExBin"
dImpulsiveness
Set variables
# Impulsiveness
iVars <- c(diffVar, "dImpulsSHMAvgMaxLR", "dImpulsSHM05ExMaxLR", "dImpulsSHMPowAvgMaxLR")
dVar <- "dAnnoyMean"

seeds <- c(418659, 7805, 38475, 65834, 1653)
Hyperparameter tuning

p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 501
mtry <- as.integer(length(iVars)/1.25)
Run model

Train preliminary model


nperm <- 5

resultsOutImpuls <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutImpuls$OOB_RMSE
[1] 0.5242683
resultsOutImpuls$OOB_MAE
[1] 0.4079044
resultsOutImpuls$Rsquared
[1] 0.8135546

Train multiple seeds model


resultsOutImpuls <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutImpuls$OOB_RMSE
[1] 0.5207893
resultsOutImpuls$OOB_MAE
[1] 0.4047467
resultsOutImpuls$Rsquared
[1] 0.8173652

# store results
resdAnnoyMnFit['Diff impuls', 'RMSE'] <- resultsOutImpuls$OOB_RMSE
resdAnnoyMnFit['Diff impuls', 'MAE'] <- resultsOutImpuls$OOB_MAE
resdAnnoyMnFit['Diff impuls', 'Rsquared'] <- resultsOutImpuls$Rsquared
resdAnnoyMnPermImp$DiffImpuls <- resultsOutImpuls$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutImpuls.conimp <- arrange(resultsOutImpuls$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutImpuls.conimp) + geom_col(aes(x=factor(rownames(resultsOutImpuls.conimp), levels=rownames(resultsOutImpuls.conimp)), y=CondPermImp), fill=mycolours[6], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (mean change in annoyance)") + ggtitle("dImpulsiveness") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtAdAnnoyMndImpulsConPermimp.svg", width=8, height=2, path=file.path(outFigPath, "svg"))
  unlink("PtAdAnnoyMndImpulsConPermimp.svg")
  
  ggsave(filename="PtAdAnnoyMndImpulsConPermimp.pdf", width=8, height=2, path=file.path(outFigPath, "pdf"))
  unlink("PtAdAnnoyMndImpulsConPermimp.pdf")
}

Selected metric


dImpulsVar <- "dImpulsSHM05ExMaxLR"

dSQM and loudness comparison

Now the highest importance dSQMs are ranked against each other, controlling for loudness difference.

Include dtonal loudness
Set variables

iVars <- c(diffVar, dSharpVar, dTonLdVar, dFluctVar, dRoughVar, dImpulsVar)
dVar <- "dAnnoyMean"

seeds <- c(98465, 54163, 6541, 36485, 849675)
Hyperparameter tuning

p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 251
mtry <- as.integer(length(iVars)/1.75)
Run model

Train preliminary model


nperm <- 5

resultsOutSQMs1 <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutSQMs1$OOB_RMSE
[1] 0.4579162
resultsOutSQMs1$OOB_MAE
[1] 0.3597023
resultsOutSQMs1$Rsquared
[1] 0.8618785

Train multiple seeds model


resultsOutSQMs1 <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutSQMs1$OOB_RMSE
[1] 0.460312
resultsOutSQMs1$OOB_MAE
[1] 0.363146
resultsOutSQMs1$Rsquared
[1] 0.8597486

# store results
resdAnnoyMnFit['Diff SQMs inc tonal loud', 'RMSE'] <- resultsOutSQMs1$OOB_RMSE
resdAnnoyMnFit['Diff SQMs inc tonal loud', 'MAE'] <- resultsOutSQMs1$OOB_MAE
resdAnnoyMnFit['Diff SQMs inc tonal loud', 'Rsquared'] <- resultsOutSQMs1$Rsquared
resdAnnoyMnPermImp$DiffSQMs1 <- resultsOutSQMs1$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutSQMs1.conimp <- arrange(resultsOutSQMs1$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutSQMs1.conimp) + geom_col(aes(x=factor(rownames(resultsOutSQMs1.conimp), levels=rownames(resultsOutSQMs1.conimp)), y=CondPermImp), fill=mycolours[7], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (mean change in annoyance)") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip(ylim=c(0, 1.2))
pBar


if (saveplots){
  ggsave(filename="PtAdAnnoyMnDiffSQMsTonLdConPermimp.svg", width=8, height=2.4, path=file.path(outFigPath, "svg"))
  unlink("PtAdAnnoyMnDiffSQMsTonLdConPermimp.svg")
  
  ggsave(filename="PtAdAnnoyMnDiffSQMsTonLdConPermimp.pdf", width=8, height=2.4, path=file.path(outFigPath, "pdf"))
  unlink("PtAdAnnoyMnDiffSQMsTonLdConPermimp.pdf")
}
Exclude tonal loudness
Set variables

iVars <- c(diffVar, dSharpVar, dTonalVar, dFluctVar, dRoughVar, dImpulsVar)
dVar <- "dAnnoyMean"

seeds <- c(49865, 7852, 845961, 410583, 36748)
Hyperparameter tuning

p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 4001
mtry <- as.integer(length(iVars)/1.75)
Run model

Train preliminary model


nperm <- 5

resultsOutSQMs2 <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutSQMs2$OOB_RMSE
[1] 0.458182
resultsOutSQMs2$OOB_MAE
[1] 0.360887
resultsOutSQMs2$Rsquared
[1] 0.862422

Train multiple seeds model


resultsOutSQMs2 <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutSQMs2$OOB_RMSE
[1] 0.4569997
resultsOutSQMs2$OOB_MAE
[1] 0.3596057
resultsOutSQMs2$Rsquared
[1] 0.863165

# store results
resdAnnoyMnFit['Diff SQMs no tonal loud', 'RMSE'] <- resultsOutSQMs2$OOB_RMSE
resdAnnoyMnFit['Diff SQMs no tonal loud', 'RMSE'] <- resultsOutSQMs2$OOB_MAE
resdAnnoyMnFit['Diff SQMs no tonal loud', 'Rsquared'] <- resultsOutSQMs2$Rsquared
resdAnnoyMnPermImp$DiffSQMs2 <- resultsOutSQMs2$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutSQMs2.conimp <- arrange(resultsOutSQMs2$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutSQMs2.conimp) + geom_col(aes(x=factor(rownames(resultsOutSQMs2.conimp), levels=rownames(resultsOutSQMs2.conimp)), y=CondPermImp), fill=mycolours[7], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (mean change in annoyance)") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip(ylim=c(0, 1.2))
pBar


if (saveplots){
  ggsave(filename="PtAdAnnoyMnDiffSQMsNoTonLdConPermimp.svg", width=8, height=2.4, path=file.path(outFigPath, "svg"))
  unlink("PtAdAnnoyMnDiffSQMsNoTonLdConPermimp.svg")
  
  ggsave(filename="PtAdAnnoyMnDiffSQMsNoTonLdConPermimp.pdf", width=8, height=2.4, path=file.path(outFigPath, "pdf"))
  unlink("PtAdAnnoyMnDiffSQMsNoTonLdConPermimp.pdf")
}

Save the results outputs to file


if (savedata){
  utils::write.csv(resdAnnoyMnFit, paste(outDataPath, "\\ptACRFdAnnoyMnOOBFit.csv", sep=""))
  ii <- 0
  temp = list()
  for (res in resdAnnoyMnPermImp){
    ii <- ii + 1
    temp[[ii]] <- as.data.frame(resdAnnoyMnPermImp[ii])
    names(temp[[ii]]) <- names(resdAnnoyMnPermImp[ii])
  }
  openxlsx::write.xlsx(temp, paste(outDataPath, "\\ptACRFdAnnoyMnConPermimp.xlsx",
                                   sep=""),
                       rowNames=TRUE)
}

(Change to) High annoyance

Initialise results output variables

resdHiAnnoyFit <- data.frame(RMSE = numeric(),
                             MAE = numeric(),
                             Rsquared = numeric())
resdHiAnnoyPermImp <- list()

All variables (absolute and difference)

Remove ambient only stimuli

Here, the ‘ambient only’ stimuli are removed, as the analysis cannot handle missing values for dB metrics.

stimDataANum <- stimDataANum[complete.cases(stimDataANum),]
stimDataANum$UASLAeq <- as.numeric(stimDataANum$UASLAeq)
stimDataANum$SNRlevel <- as.numeric(stimDataANum$SNRlevel)

Set variables


iVars <- names(stimDataANum)[which(names(stimDataANum) == 'UASLAeq'):which(names(stimDataANum) == 'UASImpulsSHM05ExMaxLR')]
iVars <- iVars[! iVars %in% 'SNRlevel']
iVars <- c(iVars,
           names(stimDataANum)[which(colnames(stimDataANum)=="LAeqLAF90diff"):
                               which(colnames(stimDataANum)=="dImpulsSHM05ExMaxLR")], "SNRlevel")
dVar <- "dHighAnnoyPc"

seeds <- c(2, 312, 1897, 465978, 821659)

Hyperparameter tuning


p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
              ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 501
mtry <- as.integer(length(iVars)/1.75)

Run model

Train preliminary model


nperm <- 5

resultsOutAbsDiffs <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutAbsDiffs$OOB_RMSE
[1] 5.468804
resultsOutAbsDiffs$OOB_MAE
[1] 4.327614
resultsOutAbsDiffs$Rsquared
[1] 0.6347201

Train multiple seeds model


resultsOutAbsDiffs <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutAbsDiffs$OOB_RMSE
[1] 5.504329
resultsOutAbsDiffs$OOB_MAE
[1] 4.353992
resultsOutAbsDiffs$Rsquared
[1] 0.6301227
# store results
resdHiAnnoyFit['All vars', 'RMSE'] <- resultsOutAbsDiffs$OOB_RMSE
resdHiAnnoyFit['All vars', 'MAE'] <- resultsOutAbsDiffs$OOB_MAE
resdHiAnnoyFit['All vars', 'Rsquared'] <- resultsOutAbsDiffs$Rsquared
resdHiAnnoyPermImp$AllVars <- resultsOutAbsDiffs$conditional_permimp

Plot results

par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutAbsDiffs.conimp <- arrange(resultsOutAbsDiffs$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutAbsDiffs.conimp) + geom_col(aes(x=factor(rownames(resultsOutAbsDiffs.conimp), levels=rownames(resultsOutAbsDiffs.conimp)), y=CondPermImp), fill=mycolours[9], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% highly annoyed)") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtAdHiAnnoyAllVarsConPermimp.svg", width=8, height=20, path=file.path(outFigPath, "svg"))
  unlink("PtAdHiAnnoyAllVarsConPermimp.svg")

  ggsave(filename="PtAdHiAnnoyAllVarsConPermimp.pdf", width=8, height=20, path=file.path(outFigPath, "pdf"))
  unlink("PtAdHiAnnoyAllVarsConPermimp.pdf")
}

# Plot only positive values

resultsOutAbsDiffs.conimpPtv <- resultsOutAbsDiffs.conimp |>
                                          rownames_to_column('Metric') |>
                                                filter_if(is.numeric, all_vars(. > 0)) |>
                                                      column_to_rownames('Metric')

pBar <- ggplot(resultsOutAbsDiffs.conimpPtv) + geom_col(aes(x=factor(rownames(resultsOutAbsDiffs.conimpPtv), levels=rownames(resultsOutAbsDiffs.conimpPtv)), y=CondPermImp), fill=mycolours[9], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% highly annoyed)") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtAdHiAnnoyAllVarsConPermimpPtv.svg", width=8, height=12, path=file.path(outFigPath, "svg"))
  unlink("PtAdHiAnnoyAllVarsConPermimp.svg")
  
  ggsave(filename="PtAdHiAnnoyAllVarsConPermimpPtv.pdf", width=8, height=12, path=file.path(outFigPath, "pdf"))
  unlink("PtAdHiAnnoyAllVarsConPermimp.pdf")
}

Absolute variables

Set variables


iVars <- names(stimDataANum)[which(names(stimDataANum) == 'UASLAeq'):which(names(stimDataANum) == 'UASImpulsSHM05ExMaxLR')]
iVars <- iVars[! iVars %in% c('SNRlevel')]
dVar <- "dHighAnnoyPc"

seeds <- c(578312, 544, 84894, 54654, 153157)

Hyperparameter tuning


p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p


if (saveplots){
  ggsave(filename="PtAdHiAnnoyAbsVarsHyperTune.svg", width=12, height=4, path=file.path(outFigPath, "svg"))
  unlink("PtAdHiAnnoyAbsVarsHyperTune.svg")

  ggsave(filename="PtAdHiAnnoyAbsVarsHyperTune.pdf", width=12, height=4, path=file.path(outFigPath, "pdf"))
  unlink("PtAdHiAnnoyAbsVarsHyperTune.pdf")
}

Selected hyperparameters


ntree <- 501
mtry <- as.integer(length(iVars)/1.25)

Run model

Train preliminary model


nperm <- 20

resultsOutAbs <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutAbs$OOB_RMSE
[1] 5.451148
resultsOutAbs$OOB_MAE
[1] 4.24412
resultsOutAbs$Rsquared
[1] 0.6356777

Train multiple seeds model


resultsOutAbs <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutAbs$OOB_RMSE
[1] 5.450724
resultsOutAbs$OOB_MAE
[1] 4.258414
resultsOutAbs$Rsquared
[1] 0.6356609

# store results
resdHiAnnoyFit['Abs vars', 'RMSE'] <- resultsOutAbs$OOB_RMSE
resdHiAnnoyFit['Abs vars', 'MAE'] <- resultsOutAbs$OOB_MAE
resdHiAnnoyFit['Abs vars', 'Rsquared'] <- resultsOutAbs$Rsquared
resdHiAnnoyPermImp$AbsVars <- resultsOutAbs$conditional_permimp

Plot results

par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutAbs.conimp <- arrange(resultsOutAbs$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutAbs.conimp) + geom_col(aes(x=factor(rownames(resultsOutAbs.conimp), levels=rownames(resultsOutAbs.conimp)), y=CondPermImp), fill=mycolours[1], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% highly annoyed)") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) +
  coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtAdHiAnnoyAbsVarsConPermimp.svg", width=8, height=11.5, path=file.path(outFigPath, "svg"))
  unlink("PtAdHiAnnoyAbsVarsConPermimp.svg")
  
  ggsave(filename="PtAdHiAnnoyAbsVarsConPermimp.pdf", width=8, height=11.5, path=file.path(outFigPath, "pdf"))
  unlink("PtAdHiAnnoyAbsVarsConPermimp.pdf")
}

# Plot only positive values
resultsOutAbs.conimpPtv <- resultsOutAbs.conimp |>
                                          rownames_to_column('Metric') |>
                                                filter_if(is.numeric, all_vars(. > 0)) |>
                                                      column_to_rownames('Metric')

pBar <- ggplot(resultsOutAbs.conimpPtv,) + geom_col(aes(x=factor(rownames(resultsOutAbs.conimpPtv), levels=rownames(resultsOutAbs.conimpPtv)), y=CondPermImp), fill=mycolours[1], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% highly annoyed)") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtAdHiAnnoyAbsVarsConPermimpPtv.svg", width=8, height=7, path=file.path(outFigPath, "svg"))
  unlink("PtAdHiAnnoyAbsVarsConPermimpPtv.svg")
  
  ggsave(filename="PtAdHiAnnoyAbsVarsConPermimpPtv.pdf", width=8, height=7, path=file.path(outFigPath, "pdf"))
  unlink("PtAdHiAnnoyAbsVarsConPermimpPtv.pdf")
}

Selected metric


absVar <- "UASLoudISO3PowAvgBin"

SQM analysis

Replace ambient only stimuli

Here, the ‘ambient only’ stimuli are replaced, as the SQM analysis can incorporate 0 values (whereas dB metrics cannot be handled in this way).


stimDataANum <- rbind(stimDataANum, stimDataA[stimDataA['Stimulus']
                                              == "A1",
                                              colnames(stimDataANum)],
                      stimDataA[stimDataA['Stimulus']
                                              == "A2",
                                              colnames(stimDataANum)])
stimDataANum <- arrange(stimDataANum, Stimulus)

Individual SQMs

Sharpness
Set variables

iVars <- c(absVar, "AmbientLAeq", "UASSharpAurISO3PowAvgMaxLR", "UASSharpAurISO305ExMaxLR", "UASSharpAurSHMPowAvgMaxLR", "UASSharpAurSHM05ExMaxLR", "UASSharpAurISO1PowAvgMaxLR", "UASSharpAurISO105ExMaxLR", "UASSharpvBISO1PowAvgMaxLR", "UASSharpvBISO105ExMaxLR", "UASSharpDINPowAvgMaxLR", "UASSharpDIN05ExMaxLR")
dVar <- "dHighAnnoyPc"

seeds <- c(7041, 905, 4984651, 6513213, 120651)
Hyperparameter tuning

p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 251
mtry <- as.integer(length(iVars)/2.75)
Run model

Train preliminary model


nperm <- 5

resultsOutSharp <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutSharp$OOB_RMSE
[1] 5.232858
resultsOutSharp$OOB_MAE
[1] 4.190305
resultsOutSharp$Rsquared
[1] 0.6681219

Train multiple seeds model


resultsOutSharp <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutSharp$OOB_RMSE
[1] 5.241474
resultsOutSharp$OOB_MAE
[1] 4.168303
resultsOutSharp$Rsquared
[1] 0.6679714
# store results
resdHiAnnoyFit['Abs sharp', 'RMSE'] <- resultsOutSharp$OOB_RMSE
resdHiAnnoyFit['Abs sharp', 'MAE'] <- resultsOutSharp$OOB_MAE
resdHiAnnoyFit['Abs sharp', 'Rsquared'] <- resultsOutSharp$Rsquared
resdHiAnnoyPermImp$AbsSharp <- resultsOutSharp$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutSharp.conimp <- arrange(resultsOutSharp$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutSharp.conimp) + geom_col(aes(x=factor(rownames(resultsOutSharp.conimp), levels=rownames(resultsOutSharp.conimp)), y=CondPermImp), fill=mycolours[2], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% highly annoyed)") + ggtitle("Sharpness") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtAdHiAnnoySharpConPermimp.svg", width=8, height=4.9, path=file.path(outFigPath, "svg"))
  unlink("PtAdHiAnnoySharpConPermimp.svg")
  
  ggsave(filename="PtAdHiAnnoySharpConPermimp.pdf", width=8, height=4.9, path=file.path(outFigPath, "pdf"))
  unlink("PtAdHiAnnoySharpConPermimp.pdf")
}

Selected metric


sharpVar <- "UASSharpAurISO305ExMaxLR"
Tonal loudness and tonality
Set variables

iVars <- c(absVar, "AmbientLAeq", "UASTonalECMAAvgMaxLR", "UASTonalSHMInt05ExMaxLR", "UASTonalSHMIntAvgMaxLR", "UASTonalECMA05ExMaxLR", "UASTonLdECMAPowAvgBin", "UASTonLdECMA05ExBin", "UASTonalAurAvgMaxLR", "UASTonalAur05ExMaxLR", "UASTonalAur10ExMaxLR")
dVar <- "dHighAnnoyPc"

seeds <- c(540, 104798, 456464, 87331, 94564)
Hyperparameter tuning

p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 251
mtry <- as.integer(length(iVars)/1.5)
Run model

Train preliminary model

# Tonality with tonal loudness

nperm <- 5

resultsOutTonal1 <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutTonal1$OOB_RMSE
[1] 5.49583
resultsOutTonal1$OOB_MAE
[1] 4.367014
resultsOutTonal1$Rsquared
[1] 0.6298765

Train multiple seeds model

# Tonality with tonal loudness

resultsOutTonal1 <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutTonal1$OOB_RMSE
[1] 5.456376
resultsOutTonal1$OOB_MAE
[1] 4.328807
resultsOutTonal1$Rsquared
[1] 0.6351314
# store results
resdHiAnnoyFit['Abs tonal inc loud', 'RMSE'] <- resultsOutTonal1$OOB_RMSE
resdHiAnnoyFit['Abs tonal inc loud', 'MAE'] <- resultsOutTonal1$OOB_MAE
resdHiAnnoyFit['Abs tonal inc loud', 'Rsquared'] <- resultsOutTonal1$Rsquared
resdHiAnnoyPermImp$AbsTonal1 <- resultsOutTonal1$conditional_permimp
Plot results

par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutTonal1.conimp <- arrange(resultsOutTonal1$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutTonal1.conimp) + geom_col(aes(x=factor(rownames(resultsOutTonal1.conimp), levels=rownames(resultsOutTonal1.conimp)), y=CondPermImp), fill=mycolours[3], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% highly annoyed)") + ggtitle("Tonality inc. tonal loudness") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip(ylim=c(-1, 70))
pBar


if (saveplots){
  ggsave(filename="PtAdHiAnnoyTonalLdConPermimp.svg", width=8, height=3.8, path=file.path(outFigPath, "svg"))
  unlink("PtAdHiAnnoyTonalLdConPermimp.svg")
  
  ggsave(filename="PtAdHiAnnoyTonalLdConPermimp.pdf", width=8, height=3.8, path=file.path(outFigPath, "pdf"))
  unlink("PtAdHiAnnoyTonalLdConPermimp.pdf")
}

Selected metric


tonLdVar <- "UASTonLdECMAPowAvgBin"
Tonality without tonal loudness
Set variables

iVars <- c(absVar, "AmbientLAeq", "UASTonalECMAAvgMaxLR", "UASTonalSHMInt05ExMaxLR", "UASTonalSHMIntAvgMaxLR", "UASTonalECMA05ExMaxLR", "UASTonalAurAvgMaxLR", "UASTonalAur05ExMaxLR", "UASTonalAur10ExMaxLR")
dVar <- "dHighAnnoyPc"

seeds <- c(156089, 5860, 10528, 89541, 4685146)
Hyperparameter tuning

p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 501
mtry <- as.integer(length(iVars)/1.25)
Run model

Train preliminary model

# Tonality

nperm <- 5

resultsOutTonal2 <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2],
                           ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm,
                           minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutTonal2$OOB_RMSE
[1] 5.450319
resultsOutTonal2$OOB_MAE
[1] 4.329233
resultsOutTonal2$Rsquared
[1] 0.6372464

Train multiple seeds model

# Tonality

resultsOutTonal2 <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutTonal2$OOB_RMSE
[1] 5.438749
resultsOutTonal2$OOB_MAE
[1] 4.317752
resultsOutTonal2$Rsquared
[1] 0.6388582

# store results
resdHiAnnoyFit['Abs tonal no loud', 'RMSE'] <- resultsOutTonal2$OOB_RMSE
resdHiAnnoyFit['Abs tonal no loud', 'MAE'] <- resultsOutTonal2$OOB_MAE
resdHiAnnoyFit['Abs tonal no loud', 'Rsquared'] <- resultsOutTonal2$Rsquared
resdHiAnnoyPermImp$AbsTonal2 <- resultsOutTonal2$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutTonal2.conimp <- arrange(resultsOutTonal2$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutTonal2.conimp) + geom_col(aes(x=factor(rownames(resultsOutTonal2.conimp), levels=rownames(resultsOutTonal2.conimp)), y=CondPermImp), fill=mycolours[3], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% highly annoyed)") + ggtitle("Tonality w/o tonal loudness") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip(ylim=c(-1, 70))
pBar


if (saveplots){
  ggsave(filename="PtAdHiAnnoyTonalConPermimp.svg", width=8, height=3.2, path=file.path(outFigPath, "svg"))
  unlink("PtAdHiAnnoyTonalConPermimp.svg")
  
  ggsave(filename="PtAdHiAnnoyTonalConPermimp.pdf", width=8, height=3.2, path=file.path(outFigPath, "pdf"))
  unlink("PtAdHiAnnoyTonalConPermimp.pdf")
}

Selected metric


tonalVar <- "UASTonalSHMInt05ExMaxLR"
Fluctuation strength
Set variables

# Fluctuation strength
iVars <- c(absVar, "AmbientLAeq", "UASFluctSHM10ExBin", "UASFluctSHM05ExBin", "UASFluctFZ10ExMaxLR", "UASFluctFZ05ExMaxLR", "UASFluctOV10ExMaxLR", "UASFluctOV05ExMaxLR")
dVar <- "dHighAnnoyPc"

seeds <- c(25107, 546098, 195, 5937, 102658)
Hyperparameter tuning

p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 501
mtry <- as.integer(length(iVars)/1.25)
Run model

Train preliminary model


nperm <- 5

resultsOutFluct <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2],
                          ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres,
                          nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutFluct$OOB_RMSE
[1] 5.663893
resultsOutFluct$OOB_MAE
[1] 4.453616
resultsOutFluct$Rsquared
[1] 0.6119349

Train multiple seeds model


resultsOutFluct <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutFluct$OOB_RMSE
[1] 5.631703
resultsOutFluct$OOB_MAE
[1] 4.416416
resultsOutFluct$Rsquared
[1] 0.6156464

# store results
resdHiAnnoyFit['Abs fluct', 'RMSE'] <- resultsOutFluct$OOB_RMSE
resdHiAnnoyFit['Abs fluct', 'MAE'] <- resultsOutFluct$OOB_MAE
resdHiAnnoyFit['Abs fluct', 'Rsquared'] <- resultsOutFluct$Rsquared
resdHiAnnoyPermImp$AbsFluct <- resultsOutFluct$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutFluct.conimp <- arrange(resultsOutFluct$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutFluct.conimp) + geom_col(aes(x=factor(rownames(resultsOutFluct.conimp), levels=rownames(resultsOutFluct.conimp)), y=CondPermImp), fill=mycolours[4], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% highly annoyed)") + ggtitle("Fluctuation strength") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtAdHiAnnoyFluctConPermimp.svg", width=8, height=2.9, path=file.path(outFigPath, "svg"))
  unlink("PtAdHiAnnoyFluctConPermimp.svg")
  
  ggsave(filename="PtAdHiAnnoyFluctConPermimp.pdf", width=8, height=2.9, path=file.path(outFigPath, "pdf"))
  unlink("PtAdHiAnnoyFluctConPermimp.pdf")
}

Selected metric


fluctVar <- "UASFluctOV10ExMaxLR"
Roughness
Set variables

# Roughness
iVars <- c(absVar, "AmbientLAeq", "UASRoughECMA10ExBin", "UASRoughECMA05ExBin", "UASRoughFZ10ExMaxLR", "UASRoughFZ05ExMaxLR", "UASRoughDW10ExMaxLR", "UASRoughDW05ExMaxLR")
dVar <- "dHighAnnoyPc"

seeds <- c(4701, 52187, 16589, 65217, 16893)
Hyperparameter tuning

p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 5501
mtry <- as.integer(length(iVars)/1.25)
Run model

Train preliminary model


nperm <- 5

resultsOutRough <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutRough$OOB_RMSE
[1] 5.582484
resultsOutRough$OOB_MAE
[1] 4.337246
resultsOutRough$Rsquared
[1] 0.6209775

Train multiple seeds model


resultsOutRough <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutRough$OOB_RMSE
[1] 5.583989
resultsOutRough$OOB_MAE
[1] 4.331894
resultsOutRough$Rsquared
[1] 0.621023
# store results
resdHiAnnoyFit['Abs rough', 'RMSE'] <- resultsOutRough$OOB_RMSE
resdHiAnnoyFit['Abs rough', 'MAE'] <- resultsOutRough$OOB_MAE
resdHiAnnoyFit['Abs rough', 'Rsquared'] <- resultsOutRough$Rsquared
resdHiAnnoyPermImp$AbsRough <- resultsOutRough$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutRough.conimp <- arrange(resultsOutRough$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutRough.conimp) + geom_col(aes(x=factor(rownames(resultsOutRough.conimp), levels=rownames(resultsOutRough.conimp)), y=CondPermImp), fill=mycolours[5], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% highly annoyed)") + ggtitle("Roughness") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtAdHiAnnoyRoughConPermimp.svg", width=8, height=2.9, path=file.path(outFigPath, "svg"))
  unlink("PtAdHiAnnoyRoughConPermimp.svg")
  
  ggsave(filename="PtAdHiAnnoyRoughConPermimp.pdf", width=8, height=2.9, path=file.path(outFigPath, "pdf"))
  unlink("PtAdHiAnnoyRoughConPermimp.pdf")
}

Selected metric


roughVar <- "UASRoughFZ05ExMaxLR"
Impulsiveness
Set variables
# Impulsiveness
iVars <- c(absVar, "AmbientLAeq", "UASImpulsSHMAvgMaxLR", "UASImpulsSHM05ExMaxLR", "UASImpulsSHMPowAvgMaxLR")
dVar <- "dHighAnnoyPc"

seeds <- c(8495, 59867, 5416, 9843, 86)
Hyperparameter tuning

p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 1501
mtry <- as.integer(length(iVars)/1.25)
Run model

Train preliminary model


nperm <- 5

resultsOutImpuls <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutImpuls$OOB_RMSE
[1] 5.494835
resultsOutImpuls$OOB_MAE
[1] 4.311435
resultsOutImpuls$Rsquared
[1] 0.6334893

Train multiple seeds model


resultsOutImpuls <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutImpuls$OOB_RMSE
[1] 5.482274
resultsOutImpuls$OOB_MAE
[1] 4.301147
resultsOutImpuls$Rsquared
[1] 0.6348031

# store results
resdHiAnnoyFit['Abs impuls', 'RMSE'] <- resultsOutImpuls$OOB_RMSE
resdHiAnnoyFit['Abs impuls', 'MAE'] <- resultsOutImpuls$OOB_MAE
resdHiAnnoyFit['Abs impuls', 'Rsquared'] <- resultsOutImpuls$Rsquared
resdHiAnnoyPermImp$AbsImpuls <- resultsOutImpuls$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutImpuls.conimp <- arrange(resultsOutImpuls$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutImpuls.conimp) + geom_col(aes(x=factor(rownames(resultsOutImpuls.conimp), levels=rownames(resultsOutImpuls.conimp)), y=CondPermImp), fill=mycolours[6], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% highly annoyed)") + ggtitle("Impulsiveness") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtAdHiAnnoyImpulsConPermimp.svg", width=8, height=2, path=file.path(outFigPath, "svg"))
  unlink("PtAdHiAnnoyImpulsConPermimp.svg")
  
  ggsave(filename="PtAdHiAnnoyImpulsConPermimp.pdf", width=8, height=2, path=file.path(outFigPath, "pdf"))
  unlink("PtAdHiAnnoyImpulsConPermimp.pdf")
}

Selected metric


impulsVar <- "UASImpulsSHMAvgMaxLR"

SQM and loudness comparison

Now the highest importance SQMs are ranked against each other, controlling for UAS loudness and ambient LAeq.

Include tonal loudness
Set variables

iVars <- c(absVar, "AmbientLAeq", sharpVar, tonLdVar, fluctVar, roughVar, impulsVar)
dVar <- "dHighAnnoyPc"

seeds <- c(70498, 4, 14986, 453, 864)
Hyperparameter tuning

p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 5501
mtry <- as.integer(length(iVars)/1.25)
Run model

Train preliminary model


nperm <- 5

resultsOutSQMs1 <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutSQMs1$OOB_RMSE
[1] 5.422008
resultsOutSQMs1$OOB_MAE
[1] 4.293746
resultsOutSQMs1$Rsquared
[1] 0.6411011

Train multiple seeds model


resultsOutSQMs1 <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutSQMs1$OOB_RMSE
[1] 5.424953
resultsOutSQMs1$OOB_MAE
[1] 4.297558
resultsOutSQMs1$Rsquared
[1] 0.6407472

# store results
resdHiAnnoyFit['Abs SQMs inc tonal loud', 'RMSE'] <- resultsOutSQMs1$OOB_RMSE
resdHiAnnoyFit['Abs SQMs inc tonal loud', 'MAE'] <- resultsOutSQMs1$OOB_MAE
resdHiAnnoyFit['Abs SQMs inc tonal loud', 'Rsquared'] <- resultsOutSQMs1$Rsquared
resdHiAnnoyPermImp$AbsSQMs1 <- resultsOutSQMs1$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutSQMs1.conimp <- arrange(resultsOutSQMs1$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutSQMs1.conimp) + geom_col(aes(x=factor(rownames(resultsOutSQMs1.conimp), levels=rownames(resultsOutSQMs1.conimp)), y=CondPermImp), fill=mycolours[7], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% highly annoyed)") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip(ylim=c(-1, 50))
pBar


if (saveplots){
  ggsave(filename="PtAdHiAnnoyAbsSQMsTonLdConPermimp.svg", width=8, height=2.4, path=file.path(outFigPath, "svg"))
  unlink("PtAdHiAnnoyAbsSQMsTonLdConPermimp.svg")
  
  ggsave(filename="PtAdHiAnnoyAbsSQMsTonLdConPermimp.pdf", width=8, height=2.4, path=file.path(outFigPath, "pdf"))
  unlink("PtAdHiAnnoyAbsSQMsTonLdConPermimp.pdf")
}
Exclude tonal loudness
Set variables

iVars <- c(absVar, "AmbientLAeq", sharpVar, tonalVar, fluctVar, roughVar, impulsVar)
dVar <- "dHighAnnoyPc"

seeds <- c(546, 57203, 270835, 60592, 8094)
Hyperparameter tuning

p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 5501
mtry <- as.integer(length(iVars)/1.25)
Run model

Train preliminary model


nperm <- 5

resultsOutSQMs2 <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutSQMs2$OOB_RMSE
[1] 5.541448
resultsOutSQMs2$OOB_MAE
[1] 4.390907
resultsOutSQMs2$Rsquared
[1] 0.6273827

Train multiple seeds model


resultsOutSQMs2 <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutSQMs2$OOB_RMSE
[1] 5.532929
resultsOutSQMs2$OOB_MAE
[1] 4.391987
resultsOutSQMs2$Rsquared
[1] 0.6285529

# store results
resdHiAnnoyFit['Abs SQMs no tonal loud', 'RMSE'] <- resultsOutSQMs2$OOB_RMSE
resdHiAnnoyFit['Abs SQMs no tonal loud', 'RMSE'] <- resultsOutSQMs2$OOB_MAE
resdHiAnnoyFit['Abs SQMs no tonal loud', 'Rsquared'] <- resultsOutSQMs2$Rsquared
resdHiAnnoyPermImp$AbsSQMs2 <- resultsOutSQMs2$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutSQMs2.conimp <- arrange(resultsOutSQMs2$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutSQMs2.conimp) + geom_col(aes(x=factor(rownames(resultsOutSQMs2.conimp), levels=rownames(resultsOutSQMs2.conimp)), y=CondPermImp), fill=mycolours[7], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% highly annoyed)") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip(ylim=c(-1, 50))
pBar


if (saveplots){
  ggsave(filename="PtAdHiAnnoyAbsSQMsNoTonLdConPermimp.svg", width=8, height=2.4, path=file.path(outFigPath, "svg"))
  unlink("PtAdHiAnnoyAbsSQMsNoTonLdConPermimp.svg")
  
  ggsave(filename="PtAdHiAnnoyAbsSQMsNoTonLdConPermimp.pdf", width=8, height=2.4, path=file.path(outFigPath, "pdf"))
  unlink("PtAdHiAnnoyAbsSQMsNoTonLdConPermimp.pdf")
}

Difference variables

Next, the difference metrics are analysed,

Remove ambient only stimuli

Here, the ‘ambient only’ stimuli are removed, as the analysis cannot handle missing values for dB metrics.

stimDataANum <- stimDataANum[complete.cases(stimDataANum),]
stimDataANum$UASLAeq <- as.numeric(stimDataANum$UASLAeq)
stimDataANum$SNRlevel <- as.numeric(stimDataANum$SNRlevel)

Set variables


iVars <- c(names(stimDataANum)[which(colnames(stimDataANum)=="LAeqLAF90diff"):
                               which(colnames(stimDataANum)=="dImpulsSHM05ExMaxLR")], "SNRlevel")
dVar <- "dHighAnnoyPc"

seeds <- c(568392, 498, 4089, 78132, 741809)

Hyperparameter tuning


p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 4001
mtry <- as.integer(length(iVars)/2.25)

Run model

Train preliminary model


nperm <- 30

resultsOutDiffs <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutDiffs$OOB_RMSE
[1] 5.719733
resultsOutDiffs$OOB_MAE
[1] 4.428596
resultsOutDiffs$Rsquared
[1] 0.6091806

Train multiple seeds model


resultsOutDiffs <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutDiffs$OOB_RMSE
[1] 5.715133
resultsOutDiffs$OOB_MAE
[1] 4.425906
resultsOutDiffs$Rsquared
[1] 0.609705

# store results
resdHiAnnoyFit['Diff vars', 'RMSE'] <- resultsOutDiffs$OOB_RMSE
resdHiAnnoyFit['Diff vars', 'MAE'] <- resultsOutDiffs$OOB_MAE
resdHiAnnoyFit['Diff vars', 'Rsquared'] <- resultsOutDiffs$Rsquared
resdHiAnnoyPermImp$DiffVars <- resultsOutDiffs$conditional_permimp

Plot results

par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutDiffs.conimp <- arrange(resultsOutDiffs$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutDiffs.conimp) + geom_col(aes(x=factor(rownames(resultsOutDiffs.conimp), levels=rownames(resultsOutDiffs.conimp)), y=CondPermImp), fill=mycolours[8], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% highly annoyed)") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtAdHiAnnoyDiffVarsConPermimp.svg", width=8, height=10, path=file.path(outFigPath, "svg"))
  unlink("PtAdHiAnnoyDiffVarsConPermimp.svg")
  
  ggsave(filename="PtAdHiAnnoyDiffVarsConPermimp.pdf", width=8, height=10, path=file.path(outFigPath, "pdf"))
  unlink("PtAdHiAnnoyDiffVarsConPermimp.pdf")
}

# Plot only positive values
resultsOutDiffs.conimpPtv <- resultsOutDiffs.conimp |>
                                        rownames_to_column('Metric') |>
                                            filter_if(is.numeric, all_vars(. > 0)) |>
                                                  column_to_rownames('Metric')

pBar <- ggplot(resultsOutDiffs.conimpPtv) + geom_col(aes(x=factor(rownames(resultsOutDiffs.conimpPtv), levels=rownames(resultsOutDiffs.conimpPtv)), y=CondPermImp), fill=mycolours[8], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% highly annoyed)") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtAdHiAnnoyDiffVarsConPermimpPtv.svg", width=8, height=8, path=file.path(outFigPath, "svg"))
  unlink("PtAdHiAnnoyDiffVarsConPermimpPtv.svg")
  
  ggsave(filename="PtAdHiAnnoyDiffVarsConPermimpPtv.pdf", width=8, height=8, path=file.path(outFigPath, "pdf"))
  unlink("PtAdHiAnnoyDiffVarsConPermimpPtv.pdf")
}

Selected metric


diffVar <- "EPNLLAeqdiff"

dSQM analysis

The ambient-only stimuli are NOT replaced here, as the difference analysis includes dB metrics.

Individual SQMs

dSharpness
Set variables

iVars <- c(diffVar, "dSharpAurISO3PowAvgMaxLR", "dSharpAurISO305ExMaxLR", "dSharpAurSHMPowAvgMaxLR", "dSharpAurSHM05ExMaxLR")
dVar <- "dHighAnnoyPc"

seeds <- c(84194, 905, 64815, 928054, 625091, 582031)
Hyperparameter tuning

p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 1501
mtry <- as.integer(length(iVars)/1.25)
Run model

Train preliminary model


nperm <- 5

resultsOutSharp <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutSharp$OOB_RMSE
[1] 5.817107
resultsOutSharp$OOB_MAE
[1] 4.431913
resultsOutSharp$Rsquared
[1] 0.5844272

Train multiple seeds model


resultsOutSharp <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutSharp$OOB_RMSE
[1] 5.794601
resultsOutSharp$OOB_MAE
[1] 4.410331
resultsOutSharp$Rsquared
[1] 0.5874878
# store results
resdHiAnnoyFit['Diff sharp', 'RMSE'] <- resultsOutSharp$OOB_RMSE
resdHiAnnoyFit['Diff sharp', 'MAE'] <- resultsOutSharp$OOB_MAE
resdHiAnnoyFit['Diff sharp', 'Rsquared'] <- resultsOutSharp$Rsquared
resdHiAnnoyPermImp$DiffSharp <- resultsOutSharp$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutSharp.conimp <- arrange(resultsOutSharp$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutSharp.conimp) + geom_col(aes(x=factor(rownames(resultsOutSharp.conimp), levels=rownames(resultsOutSharp.conimp)), y=CondPermImp), fill=mycolours[2], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% highly annoyed)") + ggtitle("dSharpness") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtAdHiAnnoydSharpConPermimp.svg", width=8, height=2.6, path=file.path(outFigPath, "svg"))
  unlink("PtAdHiAnnoydSharpConPermimp.svg")
  
  ggsave(filename="PtAdHiAnnoydSharpConPermimp.pdf", width=8, height=2.6, path=file.path(outFigPath, "pdf"))
  unlink("PtAdHiAnnoydSharpConPermimp.pdf")
}

Selected metric


dSharpVar <- "dSharpAurSHMPowAvgMaxLR"
dTonal loudness and dtonality
Set variables

iVars <- c(diffVar, "dTonalECMAAvgMaxLR", "dTonalSHMInt05ExMaxLR", "dTonalSHMIntAvgMaxLR", "dTonalECMA05ExMaxLR", "dTonLdECMAPowAvgBin", "dTonLdECMA05ExBin")
dVar <- "dHighAnnoyPc"
Hyperparameter tuning

p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p


seeds <- c(561684, 104798, 1536, 48, 48561)

Selected hyperparameters


ntree <- 1501
mtry <- as.integer(length(iVars)/1.25)
Run model

Train preliminary model

# Tonality with tonal loudness

nperm <- 5

resultsOutTonal1 <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutTonal1$OOB_RMSE
[1] 6.71205
resultsOutTonal1$OOB_MAE
[1] 5.189994
resultsOutTonal1$Rsquared
[1] 0.4460736

Train multiple seeds model

# Tonality with tonal loudness

resultsOutTonal1 <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutTonal1$OOB_RMSE
[1] 6.722309
resultsOutTonal1$OOB_MAE
[1] 5.199688
resultsOutTonal1$Rsquared
[1] 0.4443759
# store results
resdHiAnnoyFit['Diff tonal inc loud', 'RMSE'] <- resultsOutTonal1$OOB_RMSE
resdHiAnnoyFit['Diff tonal inc loud', 'MAE'] <- resultsOutTonal1$OOB_MAE
resdHiAnnoyFit['Diff tonal inc loud', 'Rsquared'] <- resultsOutTonal1$Rsquared
resdHiAnnoyPermImp$DiffTonal1 <- resultsOutTonal1$conditional_permimp
Plot results

par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutTonal1.conimp <- arrange(resultsOutTonal1$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutTonal1.conimp) + geom_col(aes(x=factor(rownames(resultsOutTonal1.conimp), levels=rownames(resultsOutTonal1.conimp)), y=CondPermImp), fill=mycolours[3], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% highly annoyed)") + ggtitle("dTonality inc. dtonal loudness") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip(ylim=c(0, 70))
pBar


if (saveplots){
  ggsave(filename="PtAdHiAnnoydTonalLdConPermimp.svg", width=8, height=2.6, path=file.path(outFigPath, "svg"))
  unlink("PtAdHiAnnoydTonalLdConPermimp.svg")
  
  ggsave(filename="PtAdHiAnnoydTonalLdConPermimp.pdf", width=8, height=2.6, path=file.path(outFigPath, "pdf"))
  unlink("PtAdHiAnnoydTonalLdConPermimp.pdf")
}

Selected metric


dTonLdVar <- "dTonLdECMAPowAvgBin"
dTonality without dtonal loudness
Set variables

iVars <- c(diffVar, "dTonalECMAAvgMaxLR", "dTonalSHMInt05ExMaxLR", "dTonalSHMIntAvgMaxLR", "dTonalECMA05ExMaxLR")
dVar <- "dHighAnnoyPc"

seeds <- c(410865, 2954, 70812, 203, 7984)
Hyperparameter tuning

p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

NA
NA

Selected hyperparameters


ntree <- 5501
mtry <- as.integer(length(iVars)/1.25)
Run model

Train preliminary model

# Tonality

nperm <- 5

resultsOutTonal2 <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutTonal2$OOB_RMSE
[1] 6.581687
resultsOutTonal2$OOB_MAE
[1] 5.067818
resultsOutTonal2$Rsquared
[1] 0.4671435

Train multiple seeds model

# Tonality

resultsOutTonal2 <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutTonal2$OOB_RMSE
[1] 6.580352
resultsOutTonal2$OOB_MAE
[1] 5.068529
resultsOutTonal2$Rsquared
[1] 0.4673965

# store results
resdHiAnnoyFit['Diff tonal no loud', 'RMSE'] <- resultsOutTonal2$OOB_RMSE
resdHiAnnoyFit['Diff tonal no loud', 'MAE'] <- resultsOutTonal2$OOB_MAE
resdHiAnnoyFit['Diff tonal no loud', 'Rsquared'] <- resultsOutTonal2$Rsquared
resdHiAnnoyPermImp$DiffTonal2 <- resultsOutTonal2$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutTonal2.conimp <- arrange(resultsOutTonal2$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutTonal2.conimp) + geom_col(aes(x=factor(rownames(resultsOutTonal2.conimp), levels=rownames(resultsOutTonal2.conimp)), y=CondPermImp), fill=mycolours[3], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% highly annoyed)") + ggtitle("dTonality w/o tonal loudness") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip(ylim=c(0, 70))
pBar


if (saveplots){
  ggsave(filename="PtAdHiAnnoydTonalConPermimp.svg", width=8, height=2, path=file.path(outFigPath, "svg"))
  unlink("PtAdHiAnnoydTonalConPermimp.svg")
  
  ggsave(filename="PtAdHiAnnoydTonalConPermimp.pdf", width=8, height=2, path=file.path(outFigPath, "pdf"))
  unlink("PtAdHiAnnoydTonalConPermimp.pdf")
}

Selected metric


dTonalVar <- "dTonalSHMIntAvgMaxLR"
dFluctuation strength
Set variables

# Fluctuation strength
iVars <- c(diffVar, "dFluctSHM10ExBin", "dFluctSHM05ExBin", "dFluctOV10ExMaxLR", "dFluctOV05ExMaxLR")
dVar <- "dHighAnnoyPc"

seeds <- c(418657, 84, 1630, 18659, 3687)
Hyperparameter tuning

p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 251
mtry <- as.integer(length(iVars)/1.25)
Run model

Train preliminary model


nperm <- 5

resultsOutFluct <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutFluct$OOB_RMSE
[1] 6.714071
resultsOutFluct$OOB_MAE
[1] 5.1887
resultsOutFluct$Rsquared
[1] 0.4455587

Train multiple seeds model


resultsOutFluct <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutFluct$OOB_RMSE
[1] 6.702409
resultsOutFluct$OOB_MAE
[1] 5.191661
resultsOutFluct$Rsquared
[1] 0.4472641

# store results
resdHiAnnoyFit['Diff fluct', 'RMSE'] <- resultsOutFluct$OOB_RMSE
resdHiAnnoyFit['Diff fluct', 'MAE'] <- resultsOutFluct$OOB_MAE
resdHiAnnoyFit['Diff fluct', 'Rsquared'] <- resultsOutFluct$Rsquared
resdHiAnnoyPermImp$DiffFluct <- resultsOutFluct$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutFluct.conimp <- arrange(resultsOutFluct$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutFluct.conimp) + geom_col(aes(x=factor(rownames(resultsOutFluct.conimp), levels=rownames(resultsOutFluct.conimp)), y=CondPermImp), fill=mycolours[4], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% highly annoyed)") + ggtitle("dFluctuation strength") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtAdHiAnnoydFluctConPermimp.svg", width=8, height=2, path=file.path(outFigPath, "svg"))
  unlink("PtAdHiAnnoyFluctConPermimp.svg")
  
  ggsave(filename="PtAdHiAnnoydFluctConPermimp.pdf", width=8, height=2, path=file.path(outFigPath, "pdf"))
  unlink("PtAdHiAnnoyFluctConPermimp.pdf")
}

Selected metric


dFluctVar <- "dFluctSHM10ExBin"
dRoughness
Set variables

# Roughness
iVars <- c(diffVar, "dRoughECMA10ExBin", "dRoughECMA05ExBin", "dRoughFZ10ExMaxLR", "dRoughFZ05ExMaxLR")
dVar <- "dHighAnnoyPc"

seeds <- c(69851, 85109, 410986, 1563, 896)
Hyperparameter tuning

p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 501
mtry <- as.integer(length(iVars)/1.25)
Run model

Train preliminary model


nperm <- 5

resultsOutRough <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)
Warning: Permutation importance rank order within 10% of max differs between seeds: increase number of trees ('ntree') or number of permutations ('nperm'), or subsample of features ('mtry')
# print model prediction results
resultsOutRough$OOB_RMSE
NULL
resultsOutRough$OOB_MAE
NULL
resultsOutRough$Rsquared
NULL

Train multiple seeds model


resultsOutRough <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutRough$OOB_RMSE
[1] 6.950843
resultsOutRough$OOB_MAE
[1] 5.259601
resultsOutRough$Rsquared
[1] 0.4054285
# store results
resdHiAnnoyFit['Diff rough', 'RMSE'] <- resultsOutRough$OOB_RMSE
resdHiAnnoyFit['Diff rough', 'MAE'] <- resultsOutRough$OOB_MAE
resdHiAnnoyFit['Diff rough', 'Rsquared'] <- resultsOutRough$Rsquared
resdHiAnnoyPermImp$DiffRough <- resultsOutRough$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutRough.conimp <- arrange(resultsOutRough$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutRough.conimp) + geom_col(aes(x=factor(rownames(resultsOutRough.conimp), levels=rownames(resultsOutRough.conimp)), y=CondPermImp), fill=mycolours[5], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% highly annoyed)") + ggtitle("dRoughness") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtAdHiAnnoydRoughConPermimp.svg", width=8, height=2, path=file.path(outFigPath, "svg"))
  unlink("PtAdHiAnnoydRoughConPermimp.svg")
  
  ggsave(filename="PtAdHiAnnoydRoughConPermimp.pdf", width=8, height=2, path=file.path(outFigPath, "pdf"))
  unlink("PtAdHiAnnoydRoughConPermimp.pdf")
}

Selected metric


dRoughVar <- "dRoughFZ05ExMaxLR"
dImpulsiveness
Set variables
# Impulsiveness
iVars <- c(diffVar, "dImpulsSHMAvgMaxLR", "dImpulsSHM05ExMaxLR", "dImpulsSHMPowAvgMaxLR")
dVar <- "dHighAnnoyPc"

seeds <- c(418659, 7805, 38475, 65834, 1653)
Hyperparameter tuning

p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 2501
mtry <- as.integer(length(iVars)/1.25)
Run model

Train preliminary model


nperm <- 5

resultsOutImpuls <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutImpuls$OOB_RMSE
[1] 6.674278
resultsOutImpuls$OOB_MAE
[1] 5.175702
resultsOutImpuls$Rsquared
[1] 0.4517669

Train multiple seeds model


resultsOutImpuls <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutImpuls$OOB_RMSE
[1] 6.673098
resultsOutImpuls$OOB_MAE
[1] 5.185144
resultsOutImpuls$Rsquared
[1] 0.4520846

# store results
resdHiAnnoyFit['Diff impuls', 'RMSE'] <- resultsOutImpuls$OOB_RMSE
resdHiAnnoyFit['Diff impuls', 'MAE'] <- resultsOutImpuls$OOB_MAE
resdHiAnnoyFit['Diff impuls', 'Rsquared'] <- resultsOutImpuls$Rsquared
resdHiAnnoyPermImp$DiffImpuls <- resultsOutImpuls$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutImpuls.conimp <- arrange(resultsOutImpuls$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutImpuls.conimp) + geom_col(aes(x=factor(rownames(resultsOutImpuls.conimp), levels=rownames(resultsOutImpuls.conimp)), y=CondPermImp), fill=mycolours[6], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% highly annoyed)") + ggtitle("dImpulsiveness") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtAdHiAnnoydImpulsConPermimp.svg", width=8, height=2, path=file.path(outFigPath, "svg"))
  unlink("PtAdHiAnnoydImpulsConPermimp.svg")
  
  ggsave(filename="PtAdHiAnnoydImpulsConPermimp.pdf", width=8, height=2, path=file.path(outFigPath, "pdf"))
  unlink("PtAdHiAnnoydImpulsConPermimp.pdf")
}

Selected metric


dImpulsVar <- "dImpulsSHMAvgMaxLR"

dSQM and loudness comparison

Now the highest importance dSQMs are ranked against each other, controlling for loudness difference.

Include dtonal loudness
Set variables

iVars <- c(diffVar, dSharpVar, dTonLdVar, dFluctVar, dRoughVar, dImpulsVar)
dVar <- "dHighAnnoyPc"

seeds <- c(98465, 54163, 6541, 36485, 849675)
Hyperparameter tuning

p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 2501
mtry <- as.integer(length(iVars)/1.75)
Run model

Train preliminary model


nperm <- 5

resultsOutSQMs1 <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)
Warning: Permutation importance rank order within 10% of max differs between seeds: increase number of trees ('ntree') or number of permutations ('nperm'), or subsample of features ('mtry')
# print model prediction results
resultsOutSQMs1$OOB_RMSE
NULL
resultsOutSQMs1$OOB_MAE
NULL
resultsOutSQMs1$Rsquared
NULL

Train multiple seeds model


resultsOutSQMs1 <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutSQMs1$OOB_RMSE
[1] 5.939049
resultsOutSQMs1$OOB_MAE
[1] 4.654886
resultsOutSQMs1$Rsquared
[1] 0.5768752

# store results
resdHiAnnoyFit['Diff SQMs inc tonal loud', 'RMSE'] <- resultsOutSQMs1$OOB_RMSE
resdHiAnnoyFit['Diff SQMs inc tonal loud', 'MAE'] <- resultsOutSQMs1$OOB_MAE
resdHiAnnoyFit['Diff SQMs inc tonal loud', 'Rsquared'] <- resultsOutSQMs1$Rsquared
resdHiAnnoyPermImp$DiffSQMs1 <- resultsOutSQMs1$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutSQMs1.conimp <- arrange(resultsOutSQMs1$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutSQMs1.conimp) + geom_col(aes(x=factor(rownames(resultsOutSQMs1.conimp), levels=rownames(resultsOutSQMs1.conimp)), y=CondPermImp), fill=mycolours[7], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% highly annoyed)") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip(ylim=c(0, 50))
pBar


if (saveplots){
  ggsave(filename="PtAdHiAnnoyDiffSQMsTonLdConPermimp.svg", width=8, height=2.4, path=file.path(outFigPath, "svg"))
  unlink("PtAdHiAnnoyDiffSQMsTonLdConPermimp.svg")
  
  ggsave(filename="PtAdHiAnnoyDiffSQMsTonLdConPermimp.pdf", width=8, height=2.4, path=file.path(outFigPath, "pdf"))
  unlink("PtAdHiAnnoyDiffSQMsTonLdConPermimp.pdf")
}
Exclude tonal loudness
Set variables

iVars <- c(diffVar, dSharpVar, dTonalVar, dFluctVar, dRoughVar, dImpulsVar)
dVar <- "dHighAnnoyPc"

seeds <- c(49865, 7852, 845961, 410583, 36748)
Hyperparameter tuning

p <- mtryTune(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 4001
mtry <- as.integer(length(iVars)/1.75)
Run model

Train preliminary model


nperm <- 5

resultsOutSQMs2 <- crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutSQMs2$OOB_RMSE
[1] 5.955857
resultsOutSQMs2$OOB_MAE
[1] 4.656295
resultsOutSQMs2$Rsquared
[1] 0.5742314

Train multiple seeds model


resultsOutSQMs2 <- multi_crfReg(dataIn=stimDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutSQMs2$OOB_RMSE
[1] 5.966773
resultsOutSQMs2$OOB_MAE
[1] 4.669058
resultsOutSQMs2$Rsquared
[1] 0.5722321

# store results
resdHiAnnoyFit['Diff SQMs no tonal loud', 'RMSE'] <- resultsOutSQMs2$OOB_RMSE
resdHiAnnoyFit['Diff SQMs no tonal loud', 'RMSE'] <- resultsOutSQMs2$OOB_MAE
resdHiAnnoyFit['Diff SQMs no tonal loud', 'Rsquared'] <- resultsOutSQMs2$Rsquared
resdHiAnnoyPermImp$DiffSQMs2 <- resultsOutSQMs2$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutSQMs2.conimp <- arrange(resultsOutSQMs2$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutSQMs2.conimp) + geom_col(aes(x=factor(rownames(resultsOutSQMs2.conimp), levels=rownames(resultsOutSQMs2.conimp)), y=CondPermImp), fill=mycolours[7], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% highly annoyed)") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip(ylim=c(0, 50))
pBar


if (saveplots){
  ggsave(filename="PtAdHiAnnoyDiffSQMsNoTonLdConPermimp.svg", width=8, height=2.4, path=file.path(outFigPath, "svg"))
  unlink("PtAdHiAnnoyDiffSQMsNoTonLdConPermimp.svg")
  
  ggsave(filename="PtAdHiAnnoyDiffSQMsNoTonLdConPermimp.pdf", width=8, height=2.4, path=file.path(outFigPath, "pdf"))
  unlink("PtAdHiAnnoyDiffSQMsNoTonLdConPermimp.pdf")
}

Save the results outputs to file


if (savedata){
  utils::write.csv(resdHiAnnoyFit, paste(outDataPath, "\\ptACRFdHiAnnoyOOBFit.csv", sep=""))
  ii <- 0
  temp = list()
  for (res in resdHiAnnoyPermImp){
    ii <- ii + 1
    temp[[ii]] <- as.data.frame(resdHiAnnoyPermImp[ii])
    names(temp[[ii]]) <- names(resdHiAnnoyPermImp[ii])
  }
  openxlsx::write.xlsx(temp, paste(outDataPath, "\\ptACRFdHiAnnoyConPermimp.xlsx",
                                   sep=""),
                       rowNames=TRUE)
}

Noticeability

Initialise results output variables

resNoticeFit <- data.frame(RMSE = numeric(),
                             MAE = numeric(),
                             Rsquared = numeric())
resNoticePermImp <- list()

All variables (absolute and difference)

Remove ambient only stimuli

Here, the ‘ambient only’ stimuli are removed, as the analysis cannot handle missing values for dB metrics.

stimNoticeDataANum <- stimNoticeDataANum[complete.cases(stimNoticeDataANum),]
stimNoticeDataANum$UASLAeq <- as.numeric(stimNoticeDataANum$UASLAeq)
stimNoticeDataANum$SNRlevel <- as.numeric(stimNoticeDataANum$SNRlevel)

Set variables


iVars <- names(stimNoticeDataANum)[which(names(stimNoticeDataANum) == 'UASLAeq'):which(names(stimNoticeDataANum) == 'UASImpulsSHM05ExMaxLR')]
iVars <- iVars[! iVars %in% 'SNRlevel']
iVars <- c(iVars,
           names(stimNoticeDataANum)[which(colnames(stimNoticeDataANum)=="LAeqLAF90diff"):
                               which(colnames(stimNoticeDataANum)=="dImpulsSHM05ExMaxLR")], "SNRlevel")
dVar <- "NoticedPcFilt"

seeds <- c(2, 312, 1897, 465978, 821659)

Hyperparameter tuning


p <- mtryTune(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 1501
mtry <- as.integer(length(iVars)/2.75)

Run model

Train preliminary model


nperm <- 10

resultsOutAbsDiffs <- crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutAbsDiffs$OOB_RMSE
[1] 10.23042
resultsOutAbsDiffs$OOB_MAE
[1] 7.618346
resultsOutAbsDiffs$Rsquared
[1] 0.9097534

Train multiple seeds model


resultsOutAbsDiffs <- multi_crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutAbsDiffs$OOB_RMSE
[1] 10.19738
resultsOutAbsDiffs$OOB_MAE
[1] 7.652439
resultsOutAbsDiffs$Rsquared
[1] 0.9103752
# store results
resNoticeFit['All vars', 'RMSE'] <- resultsOutAbsDiffs$OOB_RMSE
resNoticeFit['All vars', 'MAE'] <- resultsOutAbsDiffs$OOB_MAE
resNoticeFit['All vars', 'Rsquared'] <- resultsOutAbsDiffs$Rsquared
resNoticePermImp$AllVars <- resultsOutAbsDiffs$conditional_permimp

Plot results

par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutAbsDiffs.conimp <- arrange(resultsOutAbsDiffs$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutAbsDiffs.conimp) + geom_col(aes(x=factor(rownames(resultsOutAbsDiffs.conimp), levels=rownames(resultsOutAbsDiffs.conimp)), y=CondPermImp), fill=mycolours[9], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% UAS noticed)") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtANoticeAllVarsConPermimp.svg", width=8, height=20, path=file.path(outFigPath, "svg"))
  unlink("PtANoticeAllVarsConPermimp.svg")

  ggsave(filename="PtANoticeAllVarsConPermimp.pdf", width=8, height=20, path=file.path(outFigPath, "pdf"))
  unlink("PtANoticeAllVarsConPermimp.pdf")
}

# Plot only positive values

resultsOutAbsDiffs.conimpPtv <- resultsOutAbsDiffs.conimp |>
                                          rownames_to_column('Metric') |>
                                                filter_if(is.numeric, all_vars(. > 0)) |>
                                                      column_to_rownames('Metric')

pBar <- ggplot(resultsOutAbsDiffs.conimpPtv) + geom_col(aes(x=factor(rownames(resultsOutAbsDiffs.conimpPtv), levels=rownames(resultsOutAbsDiffs.conimpPtv)), y=CondPermImp), fill=mycolours[9], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% UAS noticed)") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtANoticeAllVarsConPermimpPtv.svg", width=8, height=12, path=file.path(outFigPath, "svg"))
  unlink("PtANoticeAllVarsConPermimp.svg")
  
  ggsave(filename="PtANoticeAllVarsConPermimpPtv.pdf", width=8, height=12, path=file.path(outFigPath, "pdf"))
  unlink("PtANoticeAllVarsConPermimp.pdf")
}

Absolute variables

Set variables


iVars <- names(stimNoticeDataANum)[which(names(stimNoticeDataANum) == 'UASLAeq'):which(names(stimNoticeDataANum) == 'UASImpulsSHM05ExMaxLR')]
iVars <- iVars[! iVars %in% c('SNRlevel')]
dVar <- "NoticedPcFilt"

seeds <- c(578312, 544, 84894, 54654, 153157)

Hyperparameter tuning


p <- mtryTune(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p


if (saveplots){
  ggsave(filename="PtANoticeAbsVarsHyperTune.svg", width=12, height=4, path=file.path(outFigPath, "svg"))
  unlink("PtANoticeAbsVarsHyperTune.svg")

  ggsave(filename="PtANoticeAbsVarsHyperTune.pdf", width=12, height=4, path=file.path(outFigPath, "pdf"))
  unlink("PtANoticeAbsVarsHyperTune.pdf")
}

Selected hyperparameters


ntree <- 2501
mtry <- as.integer(length(iVars)/1.25)

Run model

Train preliminary model


nperm <- 20

resultsOutAbs <- crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutAbs$OOB_RMSE
[1] 16.59018
resultsOutAbs$OOB_MAE
[1] 12.64339
resultsOutAbs$Rsquared
[1] 0.7829788

Train multiple seeds model


resultsOutAbs <- multi_crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutAbs$OOB_RMSE
[1] 16.50718
resultsOutAbs$OOB_MAE
[1] 12.55933
resultsOutAbs$Rsquared
[1] 0.7846705

# store results
resNoticeFit['Abs vars', 'RMSE'] <- resultsOutAbs$OOB_RMSE
resNoticeFit['Abs vars', 'MAE'] <- resultsOutAbs$OOB_MAE
resNoticeFit['Abs vars', 'Rsquared'] <- resultsOutAbs$Rsquared
resNoticePermImp$AbsVars <- resultsOutAbs$conditional_permimp

Plot results

par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutAbs.conimp <- arrange(resultsOutAbs$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutAbs.conimp) + geom_col(aes(x=factor(rownames(resultsOutAbs.conimp), levels=rownames(resultsOutAbs.conimp)), y=CondPermImp), fill=mycolours[1], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% UAS noticed)") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) +
  coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtANoticeAbsVarsConPermimp.svg", width=8, height=11.5, path=file.path(outFigPath, "svg"))
  unlink("PtANoticeAbsVarsConPermimp.svg")
  
  ggsave(filename="PtANoticeAbsVarsConPermimp.pdf", width=8, height=11.5, path=file.path(outFigPath, "pdf"))
  unlink("PtANoticeAbsVarsConPermimp.pdf")
}

# Plot only positive values
resultsOutAbs.conimpPtv <- resultsOutAbs.conimp |>
                                          rownames_to_column('Metric') |>
                                                filter_if(is.numeric, all_vars(. > 0)) |>
                                                      column_to_rownames('Metric')

pBar <- ggplot(resultsOutAbs.conimpPtv,) + geom_col(aes(x=factor(rownames(resultsOutAbs.conimpPtv), levels=rownames(resultsOutAbs.conimpPtv)), y=CondPermImp), fill=mycolours[1], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% UAS noticed)") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtANoticeAbsVarsConPermimpPtv.svg", width=8, height=7, path=file.path(outFigPath, "svg"))
  unlink("PtANoticeAbsVarsConPermimpPtv.svg")
  
  ggsave(filename="PtANoticeAbsVarsConPermimpPtv.pdf", width=8, height=7, path=file.path(outFigPath, "pdf"))
  unlink("PtANoticeAbsVarsConPermimpPtv.pdf")
}

Selected metric


absVar <- "UASPNLmaxMaxLR"

SQM analysis

Replace ambient only stimuli

Here, the ‘ambient only’ stimuli are not replaced, as the analysis cannot handle missing values for dB metrics (PNL).

# 
# stimNoticeDataANum <- rbind(stimNoticeDataANum, stimNoticeDataA[stimNoticeDataA['Stimulus']
#                                               == "A1",
#                                               colnames(stimNoticeDataANum)],
#                       stimNoticeDataA[stimNoticeDataA['Stimulus']
#                                               == "A2",
#                                               colnames(stimNoticeDataANum)])
# stimNoticeDataANum <- arrange(stimNoticeDataANum, Stimulus)

Individual SQMs

Sharpness
Set variables

iVars <- c(absVar, "AmbientLAeq", "UASSharpAurISO3PowAvgMaxLR", "UASSharpAurISO305ExMaxLR", "UASSharpAurSHMPowAvgMaxLR", "UASSharpAurSHM05ExMaxLR", "UASSharpAurISO1PowAvgMaxLR", "UASSharpAurISO105ExMaxLR", "UASSharpvBISO1PowAvgMaxLR", "UASSharpvBISO105ExMaxLR", "UASSharpDINPowAvgMaxLR", "UASSharpDIN05ExMaxLR")
dVar <- "NoticedPcFilt"

seeds <- c(7041, 905, 4984651, 6513213, 120651)
Hyperparameter tuning

p <- mtryTune(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 2501
mtry <- as.integer(length(iVars)/1.25)
Run model

Train preliminary model


nperm <- 5

resultsOutSharp <- crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)
  
# print model prediction results
resultsOutSharp$OOB_RMSE
[1] 18.90396
resultsOutSharp$OOB_MAE
[1] 14.44931
resultsOutSharp$Rsquared
[1] 0.7027075

Train multiple seeds model


resultsOutSharp <- multi_crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutSharp$OOB_RMSE
[1] 18.96332
resultsOutSharp$OOB_MAE
[1] 14.46537
resultsOutSharp$Rsquared
[1] 0.6996689
# store results
resNoticeFit['Abs sharp', 'RMSE'] <- resultsOutSharp$OOB_RMSE
resNoticeFit['Abs sharp', 'MAE'] <- resultsOutSharp$OOB_MAE
resNoticeFit['Abs sharp', 'Rsquared'] <- resultsOutSharp$Rsquared
resNoticePermImp$AbsSharp <- resultsOutSharp$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutSharp.conimp <- arrange(resultsOutSharp$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutSharp.conimp) + geom_col(aes(x=factor(rownames(resultsOutSharp.conimp), levels=rownames(resultsOutSharp.conimp)), y=CondPermImp), fill=mycolours[2], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% UAS noticed)") + ggtitle("Sharpness") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtANoticeSharpConPermimp.svg", width=8, height=4.9, path=file.path(outFigPath, "svg"))
  unlink("PtANoticeSharpConPermimp.svg")
  
  ggsave(filename="PtANoticeSharpConPermimp.pdf", width=8, height=4.9, path=file.path(outFigPath, "pdf"))
  unlink("PtANoticeSharpConPermimp.pdf")
}

Selected metric


sharpVar <- "UASSharpAurISO305ExMaxLR"
Tonal loudness and tonality
Set variables

iVars <- c(absVar, "AmbientLAeq", "UASTonalECMAAvgMaxLR", "UASTonalSHMInt05ExMaxLR", "UASTonalSHMIntAvgMaxLR", "UASTonalECMA05ExMaxLR", "UASTonLdECMAPowAvgBin", "UASTonLdECMA05ExBin", "UASTonalAurAvgMaxLR", "UASTonalAur05ExMaxLR", "UASTonalAur10ExMaxLR")
dVar <- "NoticedPcFilt"

seeds <- c(540, 104798, 456464, 87331, 94564)
Hyperparameter tuning

p <- mtryTune(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 1501
mtry <- as.integer(length(iVars)/1.25)
Run model

Train preliminary model

# Tonality with tonal loudness

nperm <- 5

resultsOutTonal1 <- crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutTonal1$OOB_RMSE
[1] 18.47209
resultsOutTonal1$OOB_MAE
[1] 14.20136
resultsOutTonal1$Rsquared
[1] 0.7179216

Train multiple seeds model

# Tonality with tonal loudness

resultsOutTonal1 <- multi_crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutTonal1$OOB_RMSE
[1] 18.19492
resultsOutTonal1$OOB_MAE
[1] 14.0021
resultsOutTonal1$Rsquared
[1] 0.7280624
# store results
resNoticeFit['Abs tonal inc loud', 'RMSE'] <- resultsOutTonal1$OOB_RMSE
resNoticeFit['Abs tonal inc loud', 'MAE'] <- resultsOutTonal1$OOB_MAE
resNoticeFit['Abs tonal inc loud', 'Rsquared'] <- resultsOutTonal1$Rsquared
resNoticePermImp$AbsTonal1 <- resultsOutTonal1$conditional_permimp
Plot results

par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutTonal1.conimp <- arrange(resultsOutTonal1$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutTonal1.conimp) + geom_col(aes(x=factor(rownames(resultsOutTonal1.conimp), levels=rownames(resultsOutTonal1.conimp)), y=CondPermImp), fill=mycolours[3], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% UAS noticed)") + ggtitle("Tonality inc. tonal loudness") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip(ylim=c(-1, 1000))
pBar


if (saveplots){
  ggsave(filename="PtANoticeTonalLdConPermimp.svg", width=8, height=3.8, path=file.path(outFigPath, "svg"))
  unlink("PtANoticeTonalLdConPermimp.svg")
  
  ggsave(filename="PtANoticeTonalLdConPermimp.pdf", width=8, height=3.8, path=file.path(outFigPath, "pdf"))
  unlink("PtANoticeTonalLdConPermimp.pdf")
}

Selected metric


tonLdVar <- "UASTonLdECMA05ExBin"
Tonality without tonal loudness
Set variables

iVars <- c(absVar, "AmbientLAeq", "UASTonalECMAAvgMaxLR", "UASTonalSHMInt05ExMaxLR", "UASTonalSHMIntAvgMaxLR", "UASTonalECMA05ExMaxLR", "UASTonalAurAvgMaxLR", "UASTonalAur05ExMaxLR", "UASTonalAur10ExMaxLR")
dVar <- "NoticedPcFilt"

seeds <- c(156089, 5860, 10528, 89541, 4685146)
Hyperparameter tuning

p <- mtryTune(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 5501
mtry <- as.integer(length(iVars)/1.25)
Run model

Train preliminary model

# Tonality

nperm <- 5

resultsOutTonal2 <- crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutTonal2$OOB_RMSE
[1] 17.0126
resultsOutTonal2$OOB_MAE
[1] 13.20926
resultsOutTonal2$Rsquared
[1] 0.7729116

Train multiple seeds model

# Tonality

resultsOutTonal2 <- multi_crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutTonal2$OOB_RMSE
[1] 17.06205
resultsOutTonal2$OOB_MAE
[1] 13.236
resultsOutTonal2$Rsquared
[1] 0.7718614

# store results
resNoticeFit['Abs tonal no loud', 'RMSE'] <- resultsOutTonal2$OOB_RMSE
resNoticeFit['Abs tonal no loud', 'MAE'] <- resultsOutTonal2$OOB_MAE
resNoticeFit['Abs tonal no loud', 'Rsquared'] <- resultsOutTonal2$Rsquared
resNoticePermImp$AbsTonal2 <- resultsOutTonal2$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutTonal2.conimp <- arrange(resultsOutTonal2$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutTonal2.conimp) + geom_col(aes(x=factor(rownames(resultsOutTonal2.conimp), levels=rownames(resultsOutTonal2.conimp)), y=CondPermImp), fill=mycolours[3], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% UAS noticed)") + ggtitle("Tonality w/o tonal loudness") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip(ylim=c(-1, 1000))
pBar


if (saveplots){
  ggsave(filename="PtANoticeTonalConPermimp.svg", width=8, height=3.2, path=file.path(outFigPath, "svg"))
  unlink("PtANoticeTonalConPermimp.svg")
  
  ggsave(filename="PtANoticeTonalConPermimp.pdf", width=8, height=3.2, path=file.path(outFigPath, "pdf"))
  unlink("PtANoticeTonalConPermimp.pdf")
}

Selected metric


tonalVar <- "UASTonalSHMInt05ExMaxLR"
Fluctuation strength
Set variables

# Fluctuation strength
iVars <- c(absVar, "AmbientLAeq", "UASFluctSHM10ExBin", "UASFluctSHM05ExBin", "UASFluctFZ10ExMaxLR", "UASFluctFZ05ExMaxLR", "UASFluctOV10ExMaxLR", "UASFluctOV05ExMaxLR")
dVar <- "NoticedPcFilt"

seeds <- c(25107, 546098, 195, 5937, 102658)
Hyperparameter tuning

p <- mtryTune(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 251
mtry <- as.integer(length(iVars)/1.5)
Run model

Train preliminary model


nperm <- 5

resultsOutFluct <- crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutFluct$OOB_RMSE
[1] 16.91354
resultsOutFluct$OOB_MAE
[1] 12.93498
resultsOutFluct$Rsquared
[1] 0.7866218

Train multiple seeds model


resultsOutFluct <- multi_crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutFluct$OOB_RMSE
[1] 16.96583
resultsOutFluct$OOB_MAE
[1] 12.82457
resultsOutFluct$Rsquared
[1] 0.7842884

# store results
resNoticeFit['Abs fluct', 'RMSE'] <- resultsOutFluct$OOB_RMSE
resNoticeFit['Abs fluct', 'MAE'] <- resultsOutFluct$OOB_MAE
resNoticeFit['Abs fluct', 'Rsquared'] <- resultsOutFluct$Rsquared
resNoticePermImp$AbsFluct <- resultsOutFluct$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutFluct.conimp <- arrange(resultsOutFluct$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutFluct.conimp) + geom_col(aes(x=factor(rownames(resultsOutFluct.conimp), levels=rownames(resultsOutFluct.conimp)), y=CondPermImp), fill=mycolours[4], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% UAS noticed)") + ggtitle("Fluctuation strength") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtANoticeFluctConPermimp.svg", width=8, height=2.9, path=file.path(outFigPath, "svg"))
  unlink("PtANoticeFluctConPermimp.svg")
  
  ggsave(filename="PtANoticeFluctConPermimp.pdf", width=8, height=2.9, path=file.path(outFigPath, "pdf"))
  unlink("PtANoticeFluctConPermimp.pdf")
}

Selected metric


fluctVar <- "UASFluctOV10ExMaxLR"
Roughness
Set variables

# Roughness
iVars <- c(absVar, "AmbientLAeq", "UASRoughECMA10ExBin", "UASRoughECMA05ExBin", "UASRoughFZ10ExMaxLR", "UASRoughFZ05ExMaxLR", "UASRoughDW10ExMaxLR", "UASRoughDW05ExMaxLR")
dVar <- "NoticedPcFilt"

seeds <- c(4701, 52187, 16589, 65217, 16893)
Hyperparameter tuning

p <- mtryTune(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 1001
mtry <- as.integer(length(iVars)/1.25)
Run model

Train preliminary model


nperm <- 5

resultsOutRough <- crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutRough$OOB_RMSE
[1] 17.26411
resultsOutRough$OOB_MAE
[1] 13.17981
resultsOutRough$Rsquared
[1] 0.7714465

Train multiple seeds model


resultsOutRough <- multi_crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutRough$OOB_RMSE
[1] 16.75907
resultsOutRough$OOB_MAE
[1] 12.82419
resultsOutRough$Rsquared
[1] 0.7847338
# store results
resNoticeFit['Abs rough', 'RMSE'] <- resultsOutRough$OOB_RMSE
resNoticeFit['Abs rough', 'MAE'] <- resultsOutRough$OOB_MAE
resNoticeFit['Abs rough', 'Rsquared'] <- resultsOutRough$Rsquared
resNoticePermImp$AbsRough <- resultsOutRough$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutRough.conimp <- arrange(resultsOutRough$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutRough.conimp) + geom_col(aes(x=factor(rownames(resultsOutRough.conimp), levels=rownames(resultsOutRough.conimp)), y=CondPermImp), fill=mycolours[5], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% UAS noticed)") + ggtitle("Roughness") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtANoticeRoughConPermimp.svg", width=8, height=2.9, path=file.path(outFigPath, "svg"))
  unlink("PtANoticeRoughConPermimp.svg")
  
  ggsave(filename="PtANoticeRoughConPermimp.pdf", width=8, height=2.9, path=file.path(outFigPath, "pdf"))
  unlink("PtANoticeRoughConPermimp.pdf")
}

Selected metric


roughVar <- "UASRoughFZ05ExMaxLR"
Impulsiveness
Set variables
# Impulsiveness
iVars <- c(absVar, "AmbientLAeq", "UASImpulsSHMAvgMaxLR", "UASImpulsSHM05ExMaxLR", "UASImpulsSHMPowAvgMaxLR")
dVar <- "NoticedPcFilt"

seeds <- c(8495, 59867, 5416, 9843, 86)
Hyperparameter tuning

p <- mtryTune(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 5501
mtry <- as.integer(length(iVars)/1.25)
Run model

Train preliminary model


nperm <- 5

resultsOutImpuls <- crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutImpuls$OOB_RMSE
[1] 16.24906
resultsOutImpuls$OOB_MAE
[1] 12.47619
resultsOutImpuls$Rsquared
[1] 0.7966846

Train multiple seeds model


resultsOutImpuls <- multi_crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutImpuls$OOB_RMSE
[1] 16.26418
resultsOutImpuls$OOB_MAE
[1] 12.46156
resultsOutImpuls$Rsquared
[1] 0.7959352

# store results
resNoticeFit['Abs impuls', 'RMSE'] <- resultsOutImpuls$OOB_RMSE
resNoticeFit['Abs impuls', 'MAE'] <- resultsOutImpuls$OOB_MAE
resNoticeFit['Abs impuls', 'Rsquared'] <- resultsOutImpuls$Rsquared
resNoticePermImp$AbsImpuls <- resultsOutImpuls$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutImpuls.conimp <- arrange(resultsOutImpuls$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutImpuls.conimp) + geom_col(aes(x=factor(rownames(resultsOutImpuls.conimp), levels=rownames(resultsOutImpuls.conimp)), y=CondPermImp), fill=mycolours[6], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% UAS noticed)") + ggtitle("Impulsiveness") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtANoticeImpulsConPermimp.svg", width=8, height=2, path=file.path(outFigPath, "svg"))
  unlink("PtANoticeImpulsConPermimp.svg")
  
  ggsave(filename="PtANoticeImpulsConPermimp.pdf", width=8, height=2, path=file.path(outFigPath, "pdf"))
  unlink("PtANoticeImpulsConPermimp.pdf")
}

Selected metric


impulsVar <- "UASImpulsSHMAvgMaxLR"

SQM and loudness comparison

Now the highest importance SQMs are ranked against each other, controlling for UAS loudness and ambient LAeq.

Include tonal loudness
Set variables

iVars <- c(absVar, "AmbientLAeq", sharpVar, tonLdVar, fluctVar, roughVar, impulsVar)
dVar <- "NoticedPcFilt"

seeds <- c(70498, 4, 14986, 453, 864)
Hyperparameter tuning

p <- mtryTune(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 251
mtry <- as.integer(length(iVars)/1.25)
Run model

Train preliminary model


nperm <- 5

resultsOutSQMs1 <- crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutSQMs1$OOB_RMSE
[1] 18.88386
resultsOutSQMs1$OOB_MAE
[1] 14.50936
resultsOutSQMs1$Rsquared
[1] 0.7014957

Train multiple seeds model


resultsOutSQMs1 <- multi_crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutSQMs1$OOB_RMSE
[1] 18.76572
resultsOutSQMs1$OOB_MAE
[1] 14.41058
resultsOutSQMs1$Rsquared
[1] 0.7076868

# store results
resNoticeFit['Abs SQMs inc tonal loud', 'RMSE'] <- resultsOutSQMs1$OOB_RMSE
resNoticeFit['Abs SQMs inc tonal loud', 'MAE'] <- resultsOutSQMs1$OOB_MAE
resNoticeFit['Abs SQMs inc tonal loud', 'Rsquared'] <- resultsOutSQMs1$Rsquared
resNoticePermImp$AbsSQMs1 <- resultsOutSQMs1$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutSQMs1.conimp <- arrange(resultsOutSQMs1$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutSQMs1.conimp) + geom_col(aes(x=factor(rownames(resultsOutSQMs1.conimp), levels=rownames(resultsOutSQMs1.conimp)), y=CondPermImp), fill=mycolours[7], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% UAS noticed)") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip(ylim=c(-1, 800))
pBar


if (saveplots){
  ggsave(filename="PtANoticeAbsSQMsTonLdConPermimp.svg", width=8, height=2.4, path=file.path(outFigPath, "svg"))
  unlink("PtANoticeAbsSQMsTonLdConPermimp.svg")
  
  ggsave(filename="PtANoticeAbsSQMsTonLdConPermimp.pdf", width=8, height=2.4, path=file.path(outFigPath, "pdf"))
  unlink("PtANoticeAbsSQMsTonLdConPermimp.pdf")
}
Exclude tonal loudness
Set variables

iVars <- c(absVar, "AmbientLAeq", sharpVar, tonalVar, fluctVar, roughVar, impulsVar)
dVar <- "NoticedPcFilt"

seeds <- c(546, 57203, 270835, 60592, 8094)
Hyperparameter tuning

p <- mtryTune(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 2501
mtry <- as.integer(length(iVars)/1.25)
Run model

Train preliminary model


nperm <- 5

resultsOutSQMs2 <- crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutSQMs2$OOB_RMSE
[1] 18.88129
resultsOutSQMs2$OOB_MAE
[1] 14.46072
resultsOutSQMs2$Rsquared
[1] 0.7037345

Train multiple seeds model


resultsOutSQMs2 <- multi_crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutSQMs2$OOB_RMSE
[1] 18.78148
resultsOutSQMs2$OOB_MAE
[1] 14.40389
resultsOutSQMs2$Rsquared
[1] 0.7078282

# store results
resNoticeFit['Abs SQMs no tonal loud', 'RMSE'] <- resultsOutSQMs2$OOB_RMSE
resNoticeFit['Abs SQMs no tonal loud', 'RMSE'] <- resultsOutSQMs2$OOB_MAE
resNoticeFit['Abs SQMs no tonal loud', 'Rsquared'] <- resultsOutSQMs2$Rsquared
resNoticePermImp$AbsSQMs2 <- resultsOutSQMs2$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutSQMs2.conimp <- arrange(resultsOutSQMs2$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutSQMs2.conimp) + geom_col(aes(x=factor(rownames(resultsOutSQMs2.conimp), levels=rownames(resultsOutSQMs2.conimp)), y=CondPermImp), fill=mycolours[7], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% UAS noticed)") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip(ylim=c(-1, 800))
pBar


if (saveplots){
  ggsave(filename="PtANoticeAbsSQMsNoTonLdConPermimp.svg", width=8, height=2.4, path=file.path(outFigPath, "svg"))
  unlink("PtANoticeAbsSQMsNoTonLdConPermimp.svg")
  
  ggsave(filename="PtANoticeAbsSQMsNoTonLdConPermimp.pdf", width=8, height=2.4, path=file.path(outFigPath, "pdf"))
  unlink("PtANoticeAbsSQMsNoTonLdConPermimp.pdf")
}

Difference variables

Next, the difference metrics are analysed,

Remove ambient only stimuli

Here, the ‘ambient only’ stimuli are removed, as the analysis cannot handle missing values for dB metrics.

stimNoticeDataANum <- stimNoticeDataANum[complete.cases(stimNoticeDataANum),]
stimNoticeDataANum$UASLAeq <- as.numeric(stimNoticeDataANum$UASLAeq)
stimNoticeDataANum$SNRlevel <- as.numeric(stimNoticeDataANum$SNRlevel)

Set variables


iVars <- c(names(stimNoticeDataANum)[which(colnames(stimNoticeDataANum)=="LAeqLAF90diff"):
                               which(colnames(stimNoticeDataANum)=="dImpulsSHM05ExMaxLR")], "SNRlevel")
dVar <- "NoticedPcFilt"

seeds <- c(568392, 498, 4089, 78132, 741809)

Hyperparameter tuning


p <- mtryTune(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 1501
mtry <- as.integer(length(iVars)/3.5)

Run model

Train preliminary model


nperm <- 30

resultsOutDiffs <- crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutDiffs$OOB_RMSE
[1] 10.09164
resultsOutDiffs$OOB_MAE
[1] 7.746637
resultsOutDiffs$Rsquared
[1] 0.9128949

Train multiple seeds model


resultsOutDiffs <- multi_crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutDiffs$OOB_RMSE
[1] 10.15461
resultsOutDiffs$OOB_MAE
[1] 7.781117
resultsOutDiffs$Rsquared
[1] 0.9118708

# store results
resNoticeFit['Diff vars', 'RMSE'] <- resultsOutDiffs$OOB_RMSE
resNoticeFit['Diff vars', 'MAE'] <- resultsOutDiffs$OOB_MAE
resNoticeFit['Diff vars', 'Rsquared'] <- resultsOutDiffs$Rsquared
resNoticePermImp$DiffVars <- resultsOutDiffs$conditional_permimp

Plot results

par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutDiffs.conimp <- arrange(resultsOutDiffs$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutDiffs.conimp) + geom_col(aes(x=factor(rownames(resultsOutDiffs.conimp), levels=rownames(resultsOutDiffs.conimp)), y=CondPermImp), fill=mycolours[8], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% UAS noticed)") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtANoticeDiffVarsConPermimp.svg", width=8, height=10, path=file.path(outFigPath, "svg"))
  unlink("PtANoticeDiffVarsConPermimp.svg")
  
  ggsave(filename="PtANoticeDiffVarsConPermimp.pdf", width=8, height=10, path=file.path(outFigPath, "pdf"))
  unlink("PtANoticeDiffVarsConPermimp.pdf")
}

# Plot only positive values
resultsOutDiffs.conimpPtv <- resultsOutDiffs.conimp |>
                                        rownames_to_column('Metric') |>
                                            filter_if(is.numeric, all_vars(. > 0)) |>
                                                  column_to_rownames('Metric')

pBar <- ggplot(resultsOutDiffs.conimpPtv) + geom_col(aes(x=factor(rownames(resultsOutDiffs.conimpPtv), levels=rownames(resultsOutDiffs.conimpPtv)), y=CondPermImp), fill=mycolours[8], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% UAS noticed)") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtANoticeDiffVarsConPermimpPtv.svg", width=8, height=8, path=file.path(outFigPath, "svg"))
  unlink("PtANoticeDiffVarsConPermimpPtv.svg")
  
  ggsave(filename="PtANoticeDiffVarsConPermimpPtv.pdf", width=8, height=8, path=file.path(outFigPath, "pdf"))
  unlink("PtANoticeDiffVarsConPermimpPtv.pdf")
}

Selected metric


diffVar <- "Detect0p5dBMaxMaxLR"

dSQM analysis

The ambient-only stimuli are NOT replaced here, as the difference analysis includes dB metrics.

Individual SQMs

dSharpness
Set variables

iVars <- c(diffVar, "dSharpAurISO3PowAvgMaxLR", "dSharpAurISO305ExMaxLR", "dSharpAurSHMPowAvgMaxLR", "dSharpAurSHM05ExMaxLR")
dVar <- "NoticedPcFilt"

seeds <- c(84194, 905, 928054, 625091, 582031)
Hyperparameter tuning

p <- mtryTune(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 2501
mtry <- as.integer(length(iVars)/1.25)
Run model

Train preliminary model


nperm <- 5

resultsOutSharp <- crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutSharp$OOB_RMSE
[1] 10.40193
resultsOutSharp$OOB_MAE
[1] 8.108278
resultsOutSharp$Rsquared
[1] 0.9042801

Train multiple seeds model


resultsOutSharp <- multi_crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutSharp$OOB_RMSE
[1] 10.43319
resultsOutSharp$OOB_MAE
[1] 8.137405
resultsOutSharp$Rsquared
[1] 0.9035948
# store results
resNoticeFit['Diff sharp', 'RMSE'] <- resultsOutSharp$OOB_RMSE
resNoticeFit['Diff sharp', 'MAE'] <- resultsOutSharp$OOB_MAE
resNoticeFit['Diff sharp', 'Rsquared'] <- resultsOutSharp$Rsquared
resNoticePermImp$DiffSharp <- resultsOutSharp$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutSharp.conimp <- arrange(resultsOutSharp$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutSharp.conimp) + geom_col(aes(x=factor(rownames(resultsOutSharp.conimp), levels=rownames(resultsOutSharp.conimp)), y=CondPermImp), fill=mycolours[2], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% UAS noticed)") + ggtitle("dSharpness") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtANoticedSharpConPermimp.svg", width=8, height=2.6, path=file.path(outFigPath, "svg"))
  unlink("PtANoticedSharpConPermimp.svg")
  
  ggsave(filename="PtANoticedSharpConPermimp.pdf", width=8, height=2.6, path=file.path(outFigPath, "pdf"))
  unlink("PtANoticedSharpConPermimp.pdf")
}

Selected metric


sharpVar <- "dSharpAurISO305ExMaxLR"
dTonal loudness and dtonality
Set variables

iVars <- c(diffVar, "dTonalECMAAvgMaxLR", "dTonalSHMInt05ExMaxLR", "dTonalSHMIntAvgMaxLR", "dTonalECMA05ExMaxLR", "dTonLdECMAPowAvgBin", "dTonLdECMA05ExBin")
dVar <- "NoticedPcFilt"

seeds <- c(561684, 104798, 1536, 48, 48561)
Hyperparameter tuning

p <- mtryTune(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <-1501
mtry <- as.integer(length(iVars)/1.25)
Run model

Train preliminary model

# Tonality with tonal loudness

nperm <- 5

resultsOutTonal1 <- crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutTonal1$OOB_RMSE
[1] 10.46408
resultsOutTonal1$OOB_MAE
[1] 8.013044
resultsOutTonal1$Rsquared
[1] 0.9021881

Train multiple seeds model

# Tonality with tonal loudness

resultsOutTonal1 <- multi_crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutTonal1$OOB_RMSE
[1] 10.45256
resultsOutTonal1$OOB_MAE
[1] 8.001321
resultsOutTonal1$Rsquared
[1] 0.9026108
# store results
resNoticeFit['Diff tonal inc loud', 'RMSE'] <- resultsOutTonal1$OOB_RMSE
resNoticeFit['Diff tonal inc loud', 'MAE'] <- resultsOutTonal1$OOB_MAE
resNoticeFit['Diff tonal inc loud', 'Rsquared'] <- resultsOutTonal1$Rsquared
resNoticePermImp$DiffTonal1 <- resultsOutTonal1$conditional_permimp
Plot results

par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutTonal1.conimp <- arrange(resultsOutTonal1$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutTonal1.conimp) + geom_col(aes(x=factor(rownames(resultsOutTonal1.conimp), levels=rownames(resultsOutTonal1.conimp)), y=CondPermImp), fill=mycolours[3], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% UAS noticed)") + ggtitle("dTonality inc. dtonal loudness") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip(ylim=c(0, 1200))
pBar


if (saveplots){
  ggsave(filename="PtANoticedTonalLdConPermimp.svg", width=8, height=2.6, path=file.path(outFigPath, "svg"))
  unlink("PtANoticedTonalLdConPermimp.svg")
  
  ggsave(filename="PtANoticedTonalLdConPermimp.pdf", width=8, height=2.6, path=file.path(outFigPath, "pdf"))
  unlink("PtANoticedTonalLdConPermimp.pdf")
}

Selected metric


tonLdVar <- "dTonLdECMAPowAvgBin"
dTonality without dtonal loudness
Set variables

iVars <- c(diffVar, "dTonalECMAAvgMaxLR", "dTonalSHMInt05ExMaxLR", "dTonalSHMIntAvgMaxLR", "dTonalECMA05ExMaxLR")
dVar <- "NoticedPcFilt"

seeds <- c(410865, 2954, 70812, 203, 7984)
Hyperparameter tuning

p <- mtryTune(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 1501
mtry <- as.integer(length(iVars)/1.25)
Run model

Train preliminary model

# Tonality

nperm <- 5

resultsOutTonal2 <- crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutTonal2$OOB_RMSE
[1] 12.53815
resultsOutTonal2$OOB_MAE
[1] 9.798852
resultsOutTonal2$Rsquared
[1] 0.8608015

Train multiple seeds model

# Tonality

resultsOutTonal2 <- multi_crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutTonal2$OOB_RMSE
[1] 12.57501
resultsOutTonal2$OOB_MAE
[1] 9.807799
resultsOutTonal2$Rsquared
[1] 0.8595653

# store results
resNoticeFit['Diff tonal no loud', 'RMSE'] <- resultsOutTonal2$OOB_RMSE
resNoticeFit['Diff tonal no loud', 'MAE'] <- resultsOutTonal2$OOB_MAE
resNoticeFit['Diff tonal no loud', 'Rsquared'] <- resultsOutTonal2$Rsquared
resNoticePermImp$DiffTonal2 <- resultsOutTonal2$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutTonal2.conimp <- arrange(resultsOutTonal2$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutTonal2.conimp) + geom_col(aes(x=factor(rownames(resultsOutTonal2.conimp), levels=rownames(resultsOutTonal2.conimp)), y=CondPermImp), fill=mycolours[3], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% UAS noticed)") + ggtitle("dTonality w/o tonal loudness") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip(ylim=c(0, 1200))
pBar


if (saveplots){
  ggsave(filename="PtANoticedTonalConPermimp.svg", width=8, height=2, path=file.path(outFigPath, "svg"))
  unlink("PtANoticedTonalConPermimp.svg")
  
  ggsave(filename="PtANoticedTonalConPermimp.pdf", width=8, height=2, path=file.path(outFigPath, "pdf"))
  unlink("PtANoticedTonalConPermimp.pdf")
}

Selected metric


tonalVar <- "dTonalECMAAvgMaxLR"
dFluctuation strength
Set variables

# Fluctuation strength
iVars <- c(diffVar, "dFluctSHM10ExBin", "dFluctSHM05ExBin", "dFluctOV10ExMaxLR", "dFluctOV05ExMaxLR")
dVar <- "NoticedPcFilt"

seeds <- c(418657, 84, 1630, 18659, 3687)
Hyperparameter tuning

p <- mtryTune(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 1501
mtry <- as.integer(length(iVars)/1.25)
Run model

Train preliminary model


nperm <- 5

resultsOutFluct <- crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutFluct$OOB_RMSE
[1] 11.38464
resultsOutFluct$OOB_MAE
[1] 8.885649
resultsOutFluct$Rsquared
[1] 0.8846925

Train multiple seeds model


resultsOutFluct <- multi_crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutFluct$OOB_RMSE
[1] 11.39714
resultsOutFluct$OOB_MAE
[1] 8.868102
resultsOutFluct$Rsquared
[1] 0.8843449

# store results
resNoticeFit['Diff fluct', 'RMSE'] <- resultsOutFluct$OOB_RMSE
resNoticeFit['Diff fluct', 'MAE'] <- resultsOutFluct$OOB_MAE
resNoticeFit['Diff fluct', 'Rsquared'] <- resultsOutFluct$Rsquared
resNoticePermImp$DiffFluct <- resultsOutFluct$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutFluct.conimp <- arrange(resultsOutFluct$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutFluct.conimp) + geom_col(aes(x=factor(rownames(resultsOutFluct.conimp), levels=rownames(resultsOutFluct.conimp)), y=CondPermImp), fill=mycolours[4], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% UAS noticed)") + ggtitle("dFluctuation strength") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtANoticedFluctConPermimp.svg", width=8, height=2, path=file.path(outFigPath, "svg"))
  unlink("PtANoticeFluctConPermimp.svg")
  
  ggsave(filename="PtANoticedFluctConPermimp.pdf", width=8, height=2, path=file.path(outFigPath, "pdf"))
  unlink("PtANoticeFluctConPermimp.pdf")
}

Selected metric


fluctVar <- "dFluctSHM05ExBin"
dRoughness
Set variables

# Roughness
iVars <- c(diffVar, "dRoughECMA10ExBin", "dRoughECMA05ExBin", "dRoughFZ10ExMaxLR", "dRoughFZ05ExMaxLR")
dVar <- "NoticedPcFilt"

seeds <- c(69851, 85109, 410986, 1563, 896)
Hyperparameter tuning

p <- mtryTune(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 2501
mtry <- as.integer(length(iVars)/1.25)
Run model

Train preliminary model


nperm <- 5

resultsOutRough <- crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutRough$OOB_RMSE
[1] 12.37658
resultsOutRough$OOB_MAE
[1] 9.87597
resultsOutRough$Rsquared
[1] 0.8723291

Train multiple seeds model


resultsOutRough <- multi_crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutRough$OOB_RMSE
[1] 12.37394
resultsOutRough$OOB_MAE
[1] 9.849881
resultsOutRough$Rsquared
[1] 0.8718619
# store results
resNoticeFit['Diff rough', 'RMSE'] <- resultsOutRough$OOB_RMSE
resNoticeFit['Diff rough', 'MAE'] <- resultsOutRough$OOB_MAE
resNoticeFit['Diff rough', 'Rsquared'] <- resultsOutRough$Rsquared
resNoticePermImp$DiffRough <- resultsOutRough$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutRough.conimp <- arrange(resultsOutRough$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutRough.conimp) + geom_col(aes(x=factor(rownames(resultsOutRough.conimp), levels=rownames(resultsOutRough.conimp)), y=CondPermImp), fill=mycolours[5], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% UAS noticed)") + ggtitle("dRoughness") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtANoticedRoughConPermimp.svg", width=8, height=2, path=file.path(outFigPath, "svg"))
  unlink("PtANoticedRoughConPermimp.svg")
  
  ggsave(filename="PtANoticedRoughConPermimp.pdf", width=8, height=2, path=file.path(outFigPath, "pdf"))
  unlink("PtANoticedRoughConPermimp.pdf")
}

Selected metric


roughVar <- "dRoughECMA05ExBin"
dImpulsiveness
Set variables
# Impulsiveness
iVars <- c(diffVar, "dImpulsSHMAvgMaxLR", "dImpulsSHM05ExMaxLR", "dImpulsSHMPowAvgMaxLR")
dVar <- "NoticedPcFilt"

seeds <- c(418659, 7805, 38475, 65834, 1653)
Hyperparameter tuning

p <- mtryTune(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 251
mtry <- as.integer(length(iVars)/1.25)
Run model

Train preliminary model


nperm <- 5

resultsOutImpuls <- crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutImpuls$OOB_RMSE
[1] 11.85234
resultsOutImpuls$OOB_MAE
[1] 9.182759
resultsOutImpuls$Rsquared
[1] 0.8773988

Train multiple seeds model


resultsOutImpuls <- multi_crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutImpuls$OOB_RMSE
[1] 11.92896
resultsOutImpuls$OOB_MAE
[1] 9.255452
resultsOutImpuls$Rsquared
[1] 0.8757174

# store results
resNoticeFit['Diff impuls', 'RMSE'] <- resultsOutImpuls$OOB_RMSE
resNoticeFit['Diff impuls', 'MAE'] <- resultsOutImpuls$OOB_MAE
resNoticeFit['Diff impuls', 'Rsquared'] <- resultsOutImpuls$Rsquared
resNoticePermImp$DiffImpuls <- resultsOutImpuls$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutImpuls.conimp <- arrange(resultsOutImpuls$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutImpuls.conimp) + geom_col(aes(x=factor(rownames(resultsOutImpuls.conimp), levels=rownames(resultsOutImpuls.conimp)), y=CondPermImp), fill=mycolours[6], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% UAS noticed)") + ggtitle("dImpulsiveness") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip()
pBar


if (saveplots){
  ggsave(filename="PtANoticedImpulsConPermimp.svg", width=8, height=2, path=file.path(outFigPath, "svg"))
  unlink("PtANoticedImpulsConPermimp.svg")
  
  ggsave(filename="PtANoticedImpulsConPermimp.pdf", width=8, height=2, path=file.path(outFigPath, "pdf"))
  unlink("PtANoticedImpulsConPermimp.pdf")
}

Selected metric


impulsVar <- "dImpulsSHM05ExMaxLR"

dSQM and loudness comparison

Now the highest importance dSQMs are ranked against each other, controlling for loudness difference.

Include dtonal loudness
Set variables

iVars <- c(diffVar, dSharpVar, dTonLdVar, dFluctVar, dRoughVar, dImpulsVar)
dVar <- "NoticedPcFilt"

seeds <- c(98465, 54163, 6541, 36485, 849675)
Hyperparameter tuning

p <- mtryTune(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 501
mtry <- as.integer(length(iVars)/1.75)
Run model

Train preliminary model


nperm <- 5

resultsOutSQMs1 <- crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutSQMs1$OOB_RMSE
[1] 10.79004
resultsOutSQMs1$OOB_MAE
[1] 8.514653
resultsOutSQMs1$Rsquared
[1] 0.9054054

Train multiple seeds model


resultsOutSQMs1 <- multi_crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutSQMs1$OOB_RMSE
[1] 10.5503
resultsOutSQMs1$OOB_MAE
[1] 8.348676
resultsOutSQMs1$Rsquared
[1] 0.9084059

# store results
resNoticeFit['Diff SQMs inc tonal loud', 'RMSE'] <- resultsOutSQMs1$OOB_RMSE
resNoticeFit['Diff SQMs inc tonal loud', 'MAE'] <- resultsOutSQMs1$OOB_MAE
resNoticeFit['Diff SQMs inc tonal loud', 'Rsquared'] <- resultsOutSQMs1$Rsquared
resNoticePermImp$DiffSQMs1 <- resultsOutSQMs1$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutSQMs1.conimp <- arrange(resultsOutSQMs1$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutSQMs1.conimp) + geom_col(aes(x=factor(rownames(resultsOutSQMs1.conimp), levels=rownames(resultsOutSQMs1.conimp)), y=CondPermImp), fill=mycolours[7], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% UAS noticed)") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip(ylim=c(0, 600))
pBar


if (saveplots){
  ggsave(filename="PtANoticeDiffSQMsTonLdConPermimp.svg", width=8, height=2.4, path=file.path(outFigPath, "svg"))
  unlink("PtANoticeDiffSQMsTonLdConPermimp.svg")
  
  ggsave(filename="PtANoticeDiffSQMsTonLdConPermimp.pdf", width=8, height=2.4, path=file.path(outFigPath, "pdf"))
  unlink("PtANoticeDiffSQMsTonLdConPermimp.pdf")
}
Exclude tonal loudness
Set variables

iVars <- c(diffVar, dSharpVar, dTonalVar, dFluctVar, dRoughVar, dImpulsVar)
dVar <- "NoticedPcFilt"

seeds <- c(49865, 7852, 845961, 410583, 36748)
Hyperparameter tuning

p <- mtryTune(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seed=seeds[1],
             ntrees=ntrees, minsplit=minsplit, minbucket=minbucket)
p

Selected hyperparameters


ntree <- 4001
mtry <- as.integer(length(iVars)/1.75)
Run model

Train preliminary model


nperm <- 5

resultsOutSQMs2 <- crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds[1:2], ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutSQMs2$OOB_RMSE
[1] 11.8702
resultsOutSQMs2$OOB_MAE
[1] 9.243409
resultsOutSQMs2$Rsquared
[1] 0.8859168

Train multiple seeds model


resultsOutSQMs2 <- multi_crfReg(dataIn=stimNoticeDataANum, iVars=iVars, dVar=dVar, seeds=seeds, ntree=ntree, mtry=mtry, permImpCondThres=permImpCondThres, nperm=nperm, minsplit=minsplit, minbucket=minbucket)

# print model prediction results
resultsOutSQMs2$OOB_RMSE
[1] 11.81577
resultsOutSQMs2$OOB_MAE
[1] 9.205458
resultsOutSQMs2$Rsquared
[1] 0.8863226

# store results
resNoticeFit['Diff SQMs no tonal loud', 'RMSE'] <- resultsOutSQMs2$OOB_RMSE
resNoticeFit['Diff SQMs no tonal loud', 'RMSE'] <- resultsOutSQMs2$OOB_MAE
resNoticeFit['Diff SQMs no tonal loud', 'Rsquared'] <- resultsOutSQMs2$Rsquared
resNoticePermImp$DiffSQMs2 <- resultsOutSQMs2$conditional_permimp
Plot results
par(mai=c(0,3,0,0))

# plot conditional importance
resultsOutSQMs2.conimp <- arrange(resultsOutSQMs2$conditional_permimp, desc(row_number()))

pBar <- ggplot(resultsOutSQMs2.conimp) + geom_col(aes(x=factor(rownames(resultsOutSQMs2.conimp), levels=rownames(resultsOutSQMs2.conimp)), y=CondPermImp), fill=mycolours[7], width=0.5) + labs(x="Variable", y="Conditional variable permutation importance (% UAS noticed)") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2)) + coord_flip(ylim=c(0, 600))
pBar


if (saveplots){
  ggsave(filename="PtANoticeDiffSQMsNoTonLdConPermimp.svg", width=8, height=2.4, path=file.path(outFigPath, "svg"))
  unlink("PtANoticeDiffSQMsNoTonLdConPermimp.svg")
  
  ggsave(filename="PtANoticeDiffSQMsNoTonLdConPermimp.pdf", width=8, height=2.4, path=file.path(outFigPath, "pdf"))
  unlink("PtANoticeDiffSQMsNoTonLdConPermimp.pdf")
}

Save the results outputs to file


if (savedata){
  utils::write.csv(resNoticeFit, paste(outDataPath, "\\ptACRFNoticeOOBFit.csv", sep=""))
  ii <- 0
  temp = list()
  for (res in resNoticePermImp){
    ii <- ii + 1
    temp[[ii]] <- as.data.frame(resNoticePermImp[ii])
    names(temp[[ii]]) <- names(resNoticePermImp[ii])
  }
  openxlsx::write.xlsx(temp, paste(outDataPath, "\\ptACRFNoticeConPermimp.xlsx",
                                   sep=""),
                       rowNames=TRUE)
}

Part A summary

Summary of results for Part A

With tonal loudness

Absolute variables

# combine the annoyance perm importance results

# convert each result to a tibble with rownames added to a column, renaming the data column to 'dAnnoy' etc.
resdAnnoyMnAbsPermImpTbl <- as.data.frame(resdAnnoyMnPermImp$AbsSQMs1/max(resdAnnoyMnPermImp$AbsSQMs1)) |>
  tibble::rownames_to_column(var='Variable')
colnames(resdAnnoyMnAbsPermImpTbl)[2] <- "dAnnoy"

resdHiAnnoyAbsPermImpTbl <- as.data.frame(resdHiAnnoyPermImp$AbsSQMs1/max(resdHiAnnoyPermImp$AbsSQMs1)) |>
  tibble::rownames_to_column(var='Variable')
colnames(resdHiAnnoyAbsPermImpTbl)[2] <- "dHiAnnoy"

resNoticeAbsPermImpTbl <- as.data.frame(resNoticePermImp$AbsSQMs1/max(resNoticePermImp$AbsSQMs1)) |>
  tibble::rownames_to_column(var='Variable')
colnames(resNoticeAbsPermImpTbl)[2] <- "dNotice"

# merge the dataframes
resAbsPermImpTbl <- list(resdAnnoyMnAbsPermImpTbl, resdHiAnnoyAbsPermImpTbl, resNoticeAbsPermImpTbl) |>
  purrr::reduce(merge, by = c('Variable'), all = T)

# rename the columns
colnames(resAbsPermImpTbl)[2:4] <- c("Mean change in annoyance", "%HA [p(HA | 0)]", "% UAS noticed")
resAbsPermImpTbl[is.na(resAbsPermImpTbl)] <- 0

resAbs <- tidyr::pivot_longer(resAbsPermImpTbl, cols=-Variable, names_to="Outcome", values_to="Imp")

# reorder res tibble, descending by the variable Imp grouped sum and create column with new group order as a factor
resAbs <- resAbs |> mutate(Variable_sum = sum(Imp), .by=Variable) |> arrange(desc(Variable_sum)) |> group_by(Variable_sum, Variable) |>
   mutate(Order = cur_group_id()) |> mutate(Order = as.factor(Order)) |> arrange(desc(Order))

# Reorder outcome levels
resAbs$Outcome <- factor(resAbs$Outcome, levels=c("Mean change in annoyance", "%HA [p(HA | 0)]", "% UAS noticed"))

# plot res as horizontal bar chart, with Imp as y axis, Variable as x axis, Outcome as fill, and Variable_sum as order, relabel x axis with Variable names
pBar <- ggplot(resAbs) + geom_col(aes(fill=Outcome, y=Imp, x=Order), colour='grey35',  width=0.75, show.legend=TRUE) + labs(x="Variable", y="Normalised variable permutation importance") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2), legend.position = "right") + coord_flip(ylim=c(-0.1, 2)) + scale_fill_manual(values=mycolours) + scale_x_discrete(labels=unique(rev(resAbs$Variable)))
pBar


if (saveplots){
  ggsave(filename="PtAcrfAbsSQMsSummary.svg", width=8, height=4, path=file.path(outFigPath, "svg"))
  unlink("PtAcrfAbsSQMsSummary.svg")
  
  ggsave(filename="PtAcrfAbsSQMsSummary.pdf", width=8, height=4, path=file.path(outFigPath, "pdf"))
  unlink("PtAcrfAbsSQMsSummary.pdf")
}

Difference variables

# combine the annoyance perm importance results

# convert each result to a tibble with rownames added to a column, renaming the data column to 'dAnnoy' etc.
resdAnnoyMnDiffPermImpTbl <- as.data.frame(resdAnnoyMnPermImp$DiffSQMs1/max(resdAnnoyMnPermImp$DiffSQMs1)) |>
  tibble::rownames_to_column(var='Variable')
colnames(resdAnnoyMnDiffPermImpTbl)[2] <- "dAnnoy"

resdHiAnnoyDiffPermImpTbl <- as.data.frame(resdHiAnnoyPermImp$DiffSQMs1/max(resdHiAnnoyPermImp$DiffSQMs1)) |>
  tibble::rownames_to_column(var='Variable')
colnames(resdHiAnnoyDiffPermImpTbl)[2] <- "dHiAnnoy"

resNoticeDiffPermImpTbl <- as.data.frame(resNoticePermImp$DiffSQMs1/max(resNoticePermImp$DiffSQMs1)) |>
  tibble::rownames_to_column(var='Variable')
colnames(resNoticeDiffPermImpTbl)[2] <- "dNotice"

# merge the dataframes
resDiffPermImpTbl <- list(resdAnnoyMnDiffPermImpTbl, resdHiAnnoyDiffPermImpTbl, resNoticeDiffPermImpTbl) |>
  purrr::reduce(merge, by = c('Variable'), all = T)

# rename the columns
colnames(resDiffPermImpTbl)[2:4] <- c("Mean change in annoyance", "%HA [p(HA | 0)]", "% UAS noticed")
resDiffPermImpTbl[is.na(resDiffPermImpTbl)] <- 0

resDiff <- tidyr::pivot_longer(resDiffPermImpTbl, cols=-Variable, names_to="Outcome", values_to="Imp")

# reorder res tibble, descending by the variable Imp grouped sum and create column with new group order as a factor
resDiff <- resDiff |> mutate(Variable_sum = sum(Imp), .by=Variable) |> arrange(desc(Variable_sum)) |> group_by(Variable_sum, Variable) |>
   mutate(Order = cur_group_id()) |> mutate(Order = as.factor(Order)) |> arrange(desc(Order))

# Reorder outcome levels
resDiff$Outcome <- factor(resDiff$Outcome, levels=c("Mean change in annoyance", "%HA [p(HA | 0)]", "% UAS noticed"))

# plot res as horizontal bar chart, with Imp as y axis, Variable as x axis, Outcome as fill, and Variable_sum as order, relabel x axis with Variable names
pBar <- ggplot(resDiff) + geom_col(aes(fill=Outcome, y=Imp, x=Order), colour='grey35',  width=0.75, show.legend=TRUE) + labs(x="Variable", y="Normalised variable permutation importance") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2), legend.position = "right") + coord_flip(ylim=c(-0.1, 2)) + scale_fill_manual(values=mycolours) + scale_x_discrete(labels=unique(rev(resDiff$Variable)))
pBar


if (saveplots){
  ggsave(filename="PtAcrfDiffSQMsSummary.svg", width=8, height=4, path=file.path(outFigPath, "svg"))
  unlink("PtAcrfDiffSQMsSummary.svg")
  
  ggsave(filename="PtAcrfDiffSQMsSummary.pdf", width=8, height=4, path=file.path(outFigPath, "pdf"))
  unlink("PtAcrfDiffSQMsSummary.pdf")
}

No tonal loudness

Absolute variables

# combine the annoyance perm importance results

# convert each result to a tibble with rownames added to a column, renaming the data column to 'dAnnoy' etc.
resdAnnoyMnAbsPermImpNoTonLdTbl <- as.data.frame(resdAnnoyMnPermImp$AbsSQMs2/max(resdAnnoyMnPermImp$AbsSQMs2)) |>
  tibble::rownames_to_column(var='Variable')
colnames(resdAnnoyMnAbsPermImpNoTonLdTbl)[2] <- "dAnnoy"

resdHiAnnoyAbsPermImpNoTonLdTbl <- as.data.frame(resdHiAnnoyPermImp$AbsSQMs2/max(resdHiAnnoyPermImp$AbsSQMs2)) |>
  tibble::rownames_to_column(var='Variable')
colnames(resdHiAnnoyAbsPermImpNoTonLdTbl)[2] <- "dHiAnnoy"

resNoticeAbsPermImpNoTonLdTbl <- as.data.frame(resNoticePermImp$AbsSQMs2/max(resNoticePermImp$AbsSQMs2)) |>
  tibble::rownames_to_column(var='Variable')
colnames(resNoticeAbsPermImpNoTonLdTbl)[2] <- "dNotice"

# merge the dataframes
resAbsNoTonLdPermImpNoTonLdTbl <- list(resdAnnoyMnAbsPermImpNoTonLdTbl, resdHiAnnoyAbsPermImpNoTonLdTbl, resNoticeAbsPermImpNoTonLdTbl) |>
  purrr::reduce(merge, by = c('Variable'), all = T)

# rename the columns
colnames(resAbsNoTonLdPermImpNoTonLdTbl)[2:4] <- c("Mean change in annoyance", "%HA [p(HA | 0)]", "% UAS noticed")
resAbsNoTonLdPermImpNoTonLdTbl[is.na(resAbsNoTonLdPermImpNoTonLdTbl)] <- 0

resAbsNoTonLd <- tidyr::pivot_longer(resAbsNoTonLdPermImpNoTonLdTbl, cols=-Variable, names_to="Outcome", values_to="Imp")

# reorder res tibble, descending by the variable Imp grouped sum and create column with new group order as a factor
resAbsNoTonLd <- resAbsNoTonLd |> mutate(Variable_sum = sum(Imp), .by=Variable) |> arrange(desc(Variable_sum)) |> group_by(Variable_sum, Variable) |>
   mutate(Order = cur_group_id()) |> mutate(Order = as.factor(Order)) |> arrange(desc(Order))

# Reorder outcome levels
resAbsNoTonLd$Outcome <- factor(resAbsNoTonLd$Outcome, levels=c("Mean change in annoyance", "%HA [p(HA | 0)]", "% UAS noticed"))

# plot res as horizontal bar chart, with Imp as y axis, Variable as x axis, Outcome as fill, and Variable_sum as order, relabel x axis with Variable names
pBar <- ggplot(resAbsNoTonLd) + geom_col(aes(fill=Outcome, y=Imp, x=Order), colour='grey35',  width=0.75, show.legend=TRUE) + labs(x="Variable", y="Normalised variable permutation importance") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2), legend.position = "right") + coord_flip(ylim=c(-0.1, 2)) + scale_fill_manual(values=mycolours) + scale_x_discrete(labels=unique(rev(resAbsNoTonLd$Variable)))
pBar


if (saveplots){
  ggsave(filename="PtAcrfAbsSQMsNoTonLdSummary.svg", width=8, height=3.7, path=file.path(outFigPath, "svg"))
  unlink("PtAcrfAbsSQMsNoTonLdSummary.svg")
  
  ggsave(filename="PtAcrfAbsSQMsNoTonLdSummary.pdf", width=8, height=3.7, path=file.path(outFigPath, "pdf"))
  unlink("PtAcrfAbsSQMsNoTonLdSummary.pdf")
}

Difference variables

# combine the annoyance perm importance results

# convert each result to a tibble with rownames added to a column, renaming the data column to 'dAnnoy' etc.
resdAnnoyMnDiffPermImpNoTonLdTbl <- as.data.frame(resdAnnoyMnPermImp$DiffSQMs2/max(resdAnnoyMnPermImp$DiffSQMs2)) |>
  tibble::rownames_to_column(var='Variable')
colnames(resdAnnoyMnDiffPermImpNoTonLdTbl)[2] <- "dAnnoy"

resdHiAnnoyDiffPermImpNoTonLdTbl <- as.data.frame(resdHiAnnoyPermImp$DiffSQMs2/max(resdHiAnnoyPermImp$DiffSQMs2)) |>
  tibble::rownames_to_column(var='Variable')
colnames(resdHiAnnoyDiffPermImpNoTonLdTbl)[2] <- "dHiAnnoy"

resNoticeDiffPermImpNoTonLdTbl <- as.data.frame(resNoticePermImp$DiffSQMs2/max(resNoticePermImp$DiffSQMs2)) |>
  tibble::rownames_to_column(var='Variable')
colnames(resNoticeDiffPermImpNoTonLdTbl)[2] <- "dNotice"

# merge the dataframes
resDiffNoTonLdPermImpNoTonLdTbl <- list(resdAnnoyMnDiffPermImpNoTonLdTbl, resdHiAnnoyDiffPermImpNoTonLdTbl, resNoticeDiffPermImpNoTonLdTbl) |>
  purrr::reduce(merge, by = c('Variable'), all = T)

# rename the columns
colnames(resDiffNoTonLdPermImpNoTonLdTbl)[2:4] <- c("Mean change in annoyance", "%HA [p(HA | 0)]", "% UAS noticed")
resDiffNoTonLdPermImpNoTonLdTbl[is.na(resDiffNoTonLdPermImpNoTonLdTbl)] <- 0

resDiffNoTonLd <- tidyr::pivot_longer(resDiffNoTonLdPermImpNoTonLdTbl, cols=-Variable, names_to="Outcome", values_to="Imp")

# reorder res tibble, descending by the variable Imp grouped sum and create column with new group order as a factor
resDiffNoTonLd <- resDiffNoTonLd |> mutate(Variable_sum = sum(Imp), .by=Variable) |> arrange(desc(Variable_sum)) |> group_by(Variable_sum, Variable) |>
   mutate(Order = cur_group_id()) |> mutate(Order = as.factor(Order)) |> arrange(desc(Order))

# Reorder outcome levels
resDiffNoTonLd$Outcome <- factor(resDiffNoTonLd$Outcome, levels=c("Mean change in annoyance", "%HA [p(HA | 0)]", "% UAS noticed"))

# plot res as horizontal bar chart, with Imp as y axis, Variable as x axis, Outcome as fill, and Variable_sum as order, relabel x axis with Variable names
pBar <- ggplot(resDiffNoTonLd) + geom_col(aes(fill=Outcome, y=Imp, x=Order), colour='grey35',  width=0.75, show.legend=TRUE) + labs(x="Variable", y="Normalised variable permutation importance") + theme(text = element_text(family = "serif"), panel.grid=element_line(color = rgb(235, 235, 235, 100, maxColorValue = 255), linewidth = 0.25, linetype = 2), legend.position = "right") + coord_flip(ylim=c(-0.1, 2)) + scale_fill_manual(values=mycolours) + scale_x_discrete(labels=unique(rev(resDiffNoTonLd$Variable)))
pBar


if (saveplots){
  ggsave(filename="PtAcrfDiffSQMsNoTonLdSummary.svg", width=8, height=4, path=file.path(outFigPath, "svg"))
  unlink("PtAcrfDiffSQMsNoTonLdSummary.svg")
  
  ggsave(filename="PtAcrfDiffSQMsNoTonLdSummary.pdf", width=8, height=4, path=file.path(outFigPath, "pdf"))
  unlink("PtAcrfDiffSQMsNoTonLdSummary.pdf")
}

Save the results outputs to file

# Make a list of the summary results
resSummary <- list(resAbs, resDiff, resAbsNoTonLd, resDiffNoTonLd)

# Save the results
if (savedata){
  ii <- 0
  temp = list()
  for (res in resSummary){
    ii <- ii + 1
    temp[[ii]] <- data.frame(resSummary[ii])
  }
  openxlsx::write.xlsx(temp, paste(outDataPath, "\\ptACRFSummary.xlsx",
                                   sep=""),
                       rowNames=TRUE)
}
LS0tDQp0aXRsZTogIlJFRk1BUCBMaXN0ZW5pbmcgdGVzdCAxIFBhcnQgQSBhbmFseXNpczogUmFuZG9tIGZvcmVzdCB2YXJpYWJsZSBpbXBvcnRhbmNlIGlkZW50aWZpY2F0aW9uIChtZWRpYW4gcmVzcG9uc2VzKSINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0KYGBgDQoNClRoaXMgbm90ZWJvb2sgYW5hbHlzZXMgdGhlIFBhcnQgQSBkYXRhIGluIHRlcm1zIG9mIHZhcmlhYmxlIGltcG9ydGFuY2UgdXNpbmcgYSByYW5kb20gZm9yZXN0IG1vZGVsIGJhc2VkIG9uIGNvbmRpdGlvbmFsIGluZmVyZW5jZSB0cmVlcyBhbmQgYSBjb25kaXRpb25hbCBwZXJtdXRhdGlvbiB2YXJpYWJsZSBpbXBvcnRhbmNlIGFsZ29yaXRobS4NCg0KIyBTZXR1cA0KDQojIyBMb2FkIHBhY2thZ2VzDQoNCmBgYHtyfQ0KIyBsb2FkIHBhY2thZ2VzDQpsaWJyYXJ5KHRpZHlyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShwYXJ0eSkNCmxpYnJhcnkoY29uZmxpY3RlZCkNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShvcGVueGxzeCkNCmxpYnJhcnkoY2FyZXQpDQpsaWJyYXJ5KHZpcmlkaXMpDQpsaWJyYXJ5KGNvd3Bsb3QpDQojIHNldCBwYWNrYWdlIHBhcmFtZXRlcnMNCnRoZW1lX3NldCh0aGVtZV9idygpKQ0KDQpgYGANCg0KYGBge3J9DQoNCiMgcGxvdCBjb2xvdXIgc2NoZW1lDQoNCm15Y29sb3VybGlzdCA9IGxpc3QoYygwLCAxMDIsIDI1NSksIGMoMCwgMjA0LCAxNTMpLCBjKDI1NSwgMCwgMTAyKSwgYyg3NCwgMTExLCAxNTIpLCBjKDI1MSwgMTY0LCA0OSksIGMoMjA0LCAxNTMsIDI1NSksIGMoOTAsIDE5MiwgMjU1KSwgYyg4MCwgMjQ1LCAyMzMpLCBjKDI1NSwgOTAsIDE5MiksIGMoMTY0LCAyMDEsIDI0MiksIGMoMjU1LCAyNTQsIDEzOSksIGMoMjU1LCAyNDMsIDI1NSkpDQpteWNvbG91cnMgPSBtYXRyaXgoKQ0KDQpmb3IgKGlpIGluIDE6bGVuZ3RoKG15Y29sb3VybGlzdCkpew0KICBteWNvbG91cnNbaWldID0gcmdiKG15Y29sb3VybGlzdFtbaWldXVsxXS8yNTUsDQogICAgICAgICAgICAgICAgICAgICAgbXljb2xvdXJsaXN0W1tpaV1dWzJdLzI1NSwNCiAgICAgICAgICAgICAgICAgICAgICBteWNvbG91cmxpc3RbW2lpXV1bM10vMjU1KQ0KfQ0KDQojIHRvZ2dsZSB0byBzYXZlIHBsb3RzDQpzYXZlcGxvdHMgPSBUUlVFDQoNCmlmIChzYXZlcGxvdHMpew0KICAjIHNldCBvdXRwdXQgcGxvdCBkaXJlY3RvcnkNCiAgY2hvb3NlLmZpbGVzKGNhcHRpb249Ikp1c3QgY2FuY2VsIHRoaXMiLCBmaWx0ZXJzPW1hdHJpeChkYXRhPWMoIiAiLCAiICIpLCBuY29sPTIpKSAgIyB3b3JrYXJvdW5kIGZvciBidWcgaW4gUlRlcm0gY2hvb3NlLmRpcg0KICBvdXRGaWdQYXRoIDwtIHV0aWxzOjpjaG9vc2UuZGlyKGNhcHRpb249IlNlbGVjdCBvdXRwdXQgZm9sZGVyIHRvIHNhdmUgcGxvdHMgJzAzIEV4cGVyaW1lbnRcXEV4cGVyaW1lbnQgMVxcQW5hbHlzaXNcXFBsb3RzJyIpDQogIA0KICBpZiAoIWRpci5leGlzdHMoZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJzdmciKSkpe2Rpci5jcmVhdGUoZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJzdmciKSl9DQogIGlmICghZGlyLmV4aXN0cyhmaWxlLnBhdGgob3V0RmlnUGF0aCwgInBkZiIpKSl7ZGlyLmNyZWF0ZShmaWxlLnBhdGgob3V0RmlnUGF0aCwgInBkZiIpKX0NCiAgDQp9DQoNCiMgdG9nZ2xlIHRvIHNhdmUgZGF0YQ0Kc2F2ZWRhdGEgPSBUUlVFDQoNCmlmIChzYXZlZGF0YSl7DQogICMgc2V0IG91dHB1dCBwbG90IGRpcmVjdG9yeQ0KICBpZiAoc2F2ZXBsb3RzPT1GQUxTRSl7DQogICAgY2hvb3NlLmZpbGVzKGNhcHRpb249Ikp1c3QgY2FuY2VsIHRoaXMiLCBmaWx0ZXJzPW1hdHJpeChkYXRhPWMoIiAiLCAiICIpLCBuY29sPTIpKSAgIyB3b3JrYXJvdW5kIGZvciBidWcgaW4gUlRlcm0gY2hvb3NlLmRpcg0KICB9DQogIG91dERhdGFQYXRoIDwtIHV0aWxzOjpjaG9vc2UuZGlyKGNhcHRpb249IlNlbGVjdCBvdXRwdXQgZm9sZGVyIHRvIHNhdmUgZGF0YSAnMDMgRXhwZXJpbWVudFxcRXhwZXJpbWVudCAxXFxBbmFseXNpc1xcUiciKQ0KfQ0KIA0KDQpgYGANCg0KIyBJbXBvcnQgZGF0YSBhbmQgd3JhbmdsZQ0KDQojIyBQYXJ0IEENCg0KYGBge3J9DQoNCnN0aW1EYXRhQXBhdGggPC0gdXRpbHM6OmNob29zZS5maWxlcyhjYXB0aW9uPXIiKFNlbGVjdCByZWZtYXBfbGlzdGVzdDFfdGVzdGRhdGFBX0J5U3RpbS5jc3YgZnJvbSAwMyBFeHBlcmltZW50XEV4cGVyaW1lbnQgMVxBbmFseXNpc1xQb3N0UHJvY2VzcykiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcnM9bWF0cml4KGRhdGE9YygicmVmbWFwX2xpc3Rlc3QxX3Rlc3RkYXRhQV9CeVN0aW0uY3N2IiwgInJlZm1hcF9saXN0ZXN0MV90ZXN0ZGF0YUFfQnlTdGltLmNzdiIpLCBuY29sPTIpKQ0KDQpzdGltTm90aWNlRGF0YUFwYXRoIDwtIHV0aWxzOjpjaG9vc2UuZmlsZXMoY2FwdGlvbj1yIihTZWxlY3QgcmVmbWFwX2xpc3Rlc3QxX3Rlc3RkYXRhQU5vdGljZUZpbHRfQnlTdGltLmNzdiBmcm9tIDAzIEV4cGVyaW1lbnRcRXhwZXJpbWVudCAxXEFuYWx5c2lzXFBvc3RQcm9jZXNzKSIsIGZpbHRlcnM9bWF0cml4KGRhdGE9YygicmVmbWFwX2xpc3Rlc3QxX3Rlc3RkYXRhQU5vdGljZUZpbHRfQnlTdGltLmNzdiIsICJyZWZtYXBfbGlzdGVzdDFfdGVzdGRhdGFBTm90aWNlRmlsdF9CeVN0aW0uY3N2IiksIG5jb2w9MikpDQoNCnN0aW1EYXRhQSA8LSB1dGlsczo6cmVhZC5jc3Yoc3RpbURhdGFBcGF0aCwgaGVhZGVyPVRSVUUpDQpzdGltTm90aWNlRGF0YUEgPC0gdXRpbHM6OnJlYWQuY3N2KHN0aW1Ob3RpY2VEYXRhQXBhdGgsIGhlYWRlcj1UUlVFKQ0KDQpjb2xuYW1lcyhzdGltRGF0YUEpWzFdIDwtICJTdGltdWx1cyINCmNvbG5hbWVzKHN0aW1Ob3RpY2VEYXRhQSlbMV0gPC0gIlN0aW11bHVzIg0KDQojIG1ha2UgcmVzcG9uc2UgcHJvcG9ydGlvbnMgaW50byBwZXJjZW50YWdlcw0Kc3RpbURhdGFBW1snSGlnaEFubm95UGMnXV0gPC0gc3RpbURhdGFBW1snSGlnaEFubm95UHJvcCddXSoxMDANCnN0aW1EYXRhQVtbJ2RIaWdoQW5ub3lQYyddXSA8LSBzdGltRGF0YUFbWydkSGlnaEFubm95UHJvcCddXSoxMDANCg0KIyBtYWtlIHJlc3BvbnNlIHByb3BvcnRpb25zIGludG8gcGVyY2VudGFnZXMNCnN0aW1Ob3RpY2VEYXRhQVtbJ0hpZ2hBbm5veVBjRmlsdCddXSA8LSBzdGltTm90aWNlRGF0YUFbWydIaWdoQW5ub3lQcm9wRmlsdCddXSoxMDANCnN0aW1Ob3RpY2VEYXRhQVtbJ2RIaWdoQW5ub3lQY0ZpbHQnXV0gPC0gc3RpbU5vdGljZURhdGFBW1snZEhpZ2hBbm5veVByb3BGaWx0J11dKjEwMA0Kc3RpbU5vdGljZURhdGFBW1snTm90aWNlZFBjRmlsdCddXSA8LSBzdGltTm90aWNlRGF0YUFbWydOb3RpY2VkUHJvcEZpbHQnXV0qMTAwDQoNCmBgYA0KDQpgYGB7cn0NCiMgZnVuY3Rpb24gdG8gZW5jb2RlIGNhdGVnb3JpY2FsIHRvIG9yZGluYWwgbnVtZXJpYyB2YXJpYWJsZXMNCmVuY29kZV9vcmRpbmFsIDwtIGZ1bmN0aW9uKHgsIG9yZGVyPXVuaXF1ZSh4KSkgew0KICB4IDwtIGFzLm51bWVyaWMoZmFjdG9yKHgsIGxldmVscz1vcmRlciwgZXhjbHVkZT1OVUxMLCBvcmRlcj1UUlVFKSkNCiAgeA0KfQ0KDQojIGRlZmluaXRpb24gb2Ygb3JkaW5hbCB2YXJpYWJsZSBsZXZlbHMNClNOUkNhdHNBIDwtIGMoIk5vIFVBUyIsICItMTYiLCAiLTEwIiwgIi00IiwgIjIiLCAiOCIpDQpVQVNMQWVxQ2F0c0EgPC0gYygiTm8gVUFTIiwgIjQyIiwgIjQ4IiwgIjU0IiwgIjYwIikNCg0KYGBgDQoNClRoZSBhZ2dyZWdhdGVkIGRhdGEgYnkgc3RpbXVsdXMgYXJlIGFzc2lnbmVkIHRvIGEgZGF0YWZyYW1lLCByZWxldmFudCBjYXRlZ29yaWNhbCB2YXJpYWJsZXMgYXJlIGNvbnZlcnRlZCB0byBvcmRpbmFsLCBhbmQgdGhlbiB0aGUgdmFyaWFibGUgc3Vic2V0IG9mIGludGVyZXN0IGlzIHNlbGVjdGVkLCBOQSByb3dzIGRyb3BwZWQgKGllLCB0aGUgJ25vIFVBUycgc3RpbXVsaSwgYXMgdGhlIGNvbmRpdGlvbmFsIHZhcmlhYmxlIGltcG9ydGFuY2UgYWxnb3JpdGhtIGNhbm5vdCBjdXJyZW50bHkgaGFuZGxlIE5BIHZhbHVlcywgd2hpY2ggYXJlIHByZXNlbnQgaW4gYWxsIHRoZSBVQVMgZEIgbWV0cmljcyksIGFuZCBhIGZvcm11bGEgYXNzaWduZWQuDQoNCmBgYHtyfQ0KDQpzdGltRGF0YUFOdW0gPC0gZGF0YS5mcmFtZSgpDQoNCnN0aW1EYXRhQU51bSA8LSBjYmluZChzdGltRGF0YUFbLCAnU3RpbXVsdXMnXSwNCiAgICAgICAgICAgICAgICAgICAgICBzdGltRGF0YUFbLCB3aGljaChjb2xuYW1lcyhzdGltRGF0YUEpPT0iVUFTTEFlcSIpOg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoKGNvbG5hbWVzKHN0aW1EYXRhQSk9PSJTTlJsZXZlbCIpXSwNCiAgICAgICAgICAgICAgICAgICAgICBzdGltRGF0YUFbLCAiSW50ZXJtaXRSYXRpb01heExSIiwgZHJvcD1GXSwNCiAgICAgICAgICAgICAgICAgICAgICBzdGltRGF0YUFbLCB3aGljaChjb2xuYW1lcyhzdGltRGF0YUEpPT0iVUFTTEFlcU1heExSIik6DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2hpY2goY29sbmFtZXMoc3RpbURhdGFBKT09IlVBU0ltcHVsc1NITTA1RXhNYXhMUiIpXSwNCiAgICAgICAgICAgICAgICAgICAgICBzdGltRGF0YUFbLCB3aGljaChjb2xuYW1lcyhzdGltRGF0YUEpPT0iTEFlcUxBRjkwZGlmZiIpOg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoKGNvbG5hbWVzKHN0aW1EYXRhQSk9PSJkSW1wdWxzU0hNMDVFeE1heExSIildLA0KICAgICAgICAgICAgICAgICAgICAgIHN0aW1EYXRhQVssIHdoaWNoKGNvbG5hbWVzKHN0aW1EYXRhQSk9PSJWYWxlbmNlTWVkaWFuIik6DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2hpY2goY29sbmFtZXMoc3RpbURhdGFBKT09ImRIaWdoQW5ub3lQcm9wIildLA0KICAgICAgICAgICAgICAgICAgICAgIHN0aW1EYXRhQVssIHdoaWNoKGNvbG5hbWVzKHN0aW1EYXRhQSk9PSJIaWdoQW5ub3lQYyIpOg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoKGNvbG5hbWVzKHN0aW1EYXRhQSk9PSJkSGlnaEFubm95UGMiKV0pDQoNCiMgcmVtb3ZlIGR1cGxpY2F0ZWQgdmFyaWFibGVzDQpzdGltRGF0YUFOdW0gPC0gc3Vic2V0KHN0aW1EYXRhQU51bSwgc2VsZWN0ID0gLWMoVUFTTEFlcU1heExSLCBVQVNMQUVNYXhMUikpDQoNCmNvbG5hbWVzKHN0aW1EYXRhQU51bSlbMV0gPC0gIlN0aW11bHVzIg0KDQojIG1ha2UgdGhlIGNhdGVnb3JpY2FsIG91dGNvbWUgdmFyaWFibGVzIG51bWVyaWNhbCBkdW1teSBmYWN0b3JzDQojIHN0aW1EYXRhQU51bVtbJ1NOUmxldmVsJ11dIDwtIGVuY29kZV9vcmRpbmFsKHN0aW1EYXRhQVtbJ1NOUmxldmVsJ11dLCBvcmRlcj1TTlJDYXRzQSkNCiMgc3RpbURhdGFBTnVtW1snVUFTTEFlcSddXSA8LSBlbmNvZGVfb3JkaW5hbChzdGltRGF0YUFbWydVQVNMQWVxJ11dLCBvcmRlcj1VQVNMQWVxQ2F0c0EpDQoNCiMgbWFrZSB0aGUgZGlzY3JldGUgb3JkaW5hbCBvdXRjb21lIHZhcmlhYmxlcyBmYWN0b3JzDQpzdGltRGF0YUFOdW1bWydWYWxlbmNlTWVkaWFuJ11dIDwtIGZhY3RvcihzdGltRGF0YUFOdW1bWydWYWxlbmNlTWVkaWFuJ11dLCBsZXZlbHM9YygxLCAyLCAzLCA0LCA1KSwgb3JkZXI9VFJVRSkNCnN0aW1EYXRhQU51bVtbJ0Fyb3VzYWxNZWRpYW4nXV0gPC0gZmFjdG9yKHN0aW1EYXRhQU51bVtbJ0Fyb3VzYWxNZWRpYW4nXV0sIGxldmVscz1jKDEsIDIsIDMsIDQsIDUpLCBvcmRlcj1UUlVFKQ0Kc3RpbURhdGFBTnVtW1snQW5ub3lNZWRpYW4nXV0gPC0gZmFjdG9yKHN0aW1EYXRhQU51bVtbJ0Fubm95TWVkaWFuJ11dLCBsZXZlbHM9YygwLCAxLCAyLCAzLCA0LCA1LCA2LCA3LCA4LCA5LCAxMCksIG9yZGVyPVRSVUUpDQpzdGltRGF0YUFOdW1bWydkVmFsZW5jZU1lZGlhbiddXSA8LSBmYWN0b3Ioc3RpbURhdGFBTnVtW1snZFZhbGVuY2VNZWRpYW4nXV0sIGxldmVscz1jKC00LCAtMywgLTIsIC0xLCAwLCAxLCAyLCAzLCA0KSwgb3JkZXI9VFJVRSkNCnN0aW1EYXRhQU51bVtbJ2RBcm91c2FsTWVkaWFuJ11dIDwtIGZhY3RvcihzdGltRGF0YUFOdW1bWydkQXJvdXNhbE1lZGlhbiddXSwgbGV2ZWxzPWMoLTQsIC0zLCAtMiwgLTEsIDAsIDEsIDIsIDMsIDQpLCBvcmRlcj1UUlVFKQ0Kc3RpbURhdGFBTnVtW1snZEFubm95TWVkaWFuJ11dIDwtIGZhY3RvcihzdGltRGF0YUFOdW1bWydkQW5ub3lNZWRpYW4nXV0sIGxldmVscz1jKC0xMCwgLTksIC04LCAtNywgLTYsIC01LCAtNCwgLTMsIC0yLCAtMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDAsIDEsIDIsIDMsIDQsIDUsIDYsIDcsIDgsIDksIDEwKSwgb3JkZXI9VFJVRSkNCg0KYGBgDQoNCmBgYHtyfQ0KDQpzdGltTm90aWNlRGF0YUFOdW0gPC0gZGF0YS5mcmFtZSgpDQoNCnN0aW1Ob3RpY2VEYXRhQU51bSA8LSBjYmluZChzdGltTm90aWNlRGF0YUFbLCAnU3RpbXVsdXMnXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGltTm90aWNlRGF0YUFbLCB3aGljaChjb2xuYW1lcyhzdGltTm90aWNlRGF0YUEpPT0iVUFTTEFlcSIpOg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoKGNvbG5hbWVzKHN0aW1Ob3RpY2VEYXRhQSk9PSJTTlJsZXZlbCIpXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGltTm90aWNlRGF0YUFbLCAiSW50ZXJtaXRSYXRpb01heExSIiwgZHJvcD1GXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGltTm90aWNlRGF0YUFbLCB3aGljaChjb2xuYW1lcyhzdGltTm90aWNlRGF0YUEpPT0iVUFTTEFlcU1heExSIik6DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2hpY2goY29sbmFtZXMoc3RpbU5vdGljZURhdGFBKT09IlVBU0ltcHVsc1NITTA1RXhNYXhMUiIpXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGltTm90aWNlRGF0YUFbLCB3aGljaChjb2xuYW1lcyhzdGltTm90aWNlRGF0YUEpPT0iTEFlcUxBRjkwZGlmZiIpOg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoKGNvbG5hbWVzKHN0aW1Ob3RpY2VEYXRhQSk9PSJkSW1wdWxzU0hNMDVFeE1heExSIildLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0aW1Ob3RpY2VEYXRhQVssIHdoaWNoKGNvbG5hbWVzKHN0aW1Ob3RpY2VEYXRhQSk9PSJOb3RpY2VkVG90YWxGaWx0Iik6DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2hpY2goY29sbmFtZXMoc3RpbU5vdGljZURhdGFBKT09Ik5vdGljZWRQY0ZpbHQiKV0pDQoNCnN0aW1Ob3RpY2VEYXRhQU51bSA8LSBzdWJzZXQoc3RpbU5vdGljZURhdGFBTnVtLCBzZWxlY3QgPSAtYyhVQVNMQWVxTWF4TFIsIFVBU0xBRU1heExSKSkNCg0KY29sbmFtZXMoc3RpbU5vdGljZURhdGFBTnVtKVsxXSA8LSAiU3RpbXVsdXMiDQoNCiMgbWFrZSB0aGUgY2F0ZWdvcmljYWwgb3V0Y29tZSB2YXJpYWJsZXMgbnVtZXJpY2FsIGR1bW15IGZhY3RvcnMNCiMgc3RpbU5vdGljZURhdGFBTnVtW1snU05SbGV2ZWwnXV0gPC0gZW5jb2RlX29yZGluYWwoc3RpbU5vdGljZURhdGFBW1snU05SbGV2ZWwnXV0sIG9yZGVyPVNOUkNhdHNBKQ0KIyBzdGltTm90aWNlRGF0YUFOdW1bWydVQVNMQWVxJ11dIDwtIGVuY29kZV9vcmRpbmFsKHN0aW1Ob3RpY2VEYXRhQVtbJ1VBU0xBZXEnXV0sIG9yZGVyPVVBU0xBZXFDYXRzQSkNCg0KYGBgDQoNCiMgUmFuZG9tIGZvcmVzdCBmdW5jdGlvbnMNCg0KV3JpdGUgYSBmdW5jdGlvbiB0byB0cmFpbiBhIGNvbmRpdGlvbmFsLWluZmVyZW5jZSByYW5kb20gZm9yZXN0IChjcmYpIG1vZGVsIG9uIGlucHV0IGRhdGEgYWNjb3JkaW5nIHRvIGlucHV0IGZvcm11bGEsIGl0ZXJhdGUgb3ZlciBpbnB1dCByYW5kb20gc2VlZHMsIGF2ZXJhZ2UgZXJyb3IgYW5kIHZhcmlhYmxlIGltcG9ydGFuY2UgbWV0cmljcywgYW5kIG91dHB1dCBtZXRyaWNzIHdpdGggcGxvdHRlZA0KDQojIyBBdmVyYWdpbmcgb3ZlciBtdWx0aXBsZSByYW5kb20gc2VlZHMNCg0KYGBge3J9DQoNCm11bHRpX2NyZlJlZyA8LSBmdW5jdGlvbihkYXRhSW4sIGlWYXJzLCBkVmFyLCBzZWVkcywgbnRyZWUsIG10cnksIHBlcm1JbXBDb25kVGhyZXM9MC45NSwgbWluc3BsaXQ9MjAsIG1pbmJ1Y2tldD03LCBucGVybT0xKXsNCiAgIyBpbml0aWFsaXNlIHZhcmlhYmxlcw0KICBjcmZPT0JFcnJBbGwgPC0gMA0KICBjcmZPT0JSTVNFIDwtIDANCiAgY3JmT09CTUFFIDwtIDANCiAgY3JmT09CRXJyUjIgPC0gMA0KICBjcmZNYXJQZXJtSW1wVmFscyA8LSAwDQogIGNyZkNvblBlcm1JbXBWYWxzIDwtIDANCiAgY3JmTWFyUGVybUltcFZhbHNQZXJUcmVlIDwtIGRhdGEuZnJhbWUoKQ0KICBjcmZDb25QZXJtSW1wVmFsc1BlclRyZWUgPC0gZGF0YS5mcmFtZSgpDQogIA0KICBmb3IgKGl0ZXJzIGluIDE6bGVuZ3RoKHNlZWRzKSl7DQogICAgDQogICAgIyBmb3JtdWxhIGZvciByZWdyZXNzaW9uDQogICAgZm9ybVZhcnMgPC0gcmVmb3JtdWxhdGUoaVZhcnMsIGRWYXIpDQogICAgDQogICAgIyBzZXQgcmFuZG9tIHNlZWQNCiAgICBzZXQuc2VlZChzZWVkc1tpdGVyc10pDQogICAgIyB0cmFpbiBjcmYgbW9kZWwNCiAgICBjcmZNb2RlbCA8LSBwYXJ0eTo6Y2ZvcmVzdChmb3JtVmFycywgZGF0YT1kYXRhSW4sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udHJvbHM9cGFydHk6OmNmb3Jlc3RfdW5iaWFzZWQobnRyZWU9bnRyZWUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXRyeT1tdHJ5LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbnNwbGl0PW1pbnNwbGl0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbmJ1Y2tldD1taW5idWNrZXQpKQ0KICAgIA0KICAgICMgZ2V0IE9PQiBwcmVkaWN0aW9ucw0KICAgIGNyZk1vZGVsT09CIDwtIHByZWRpY3QoY3JmTW9kZWwsIE9PQj1UUlVFLCB0eXBlPSdyZXNwb25zZScpDQogICAgDQogICAgIyBnZXQgT09CIGVycm9yDQogICAgY3JmTW9kZWxPT0JFcnIgPC0gYXMubnVtZXJpYyhhcy5tYXRyaXgoYXMubnVtZXJpYyhhcy5tYXRyaXgoY3JmTW9kZWxPT0IpKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAtIGFzLm51bWVyaWMoYXMubWF0cml4KGNyZk1vZGVsQGRhdGFAZW52JHJlc3BvbnNlW1tuYW1lcyhjcmZNb2RlbEBkYXRhQGVudiRyZXNwb25zZSldXSkpKSkNCg0KICAgICMgT09CIFJNU0UsIGVycm9yIHF1YXJ0aWxlcyBhbmQgUnNxdWFyZWQNCiAgICBjcmZPT0JSTVNFIDwtIGNyZk9PQlJNU0UgKyBzcXJ0KG1lYW4oY3JmTW9kZWxPT0JFcnJeMikpDQogICAgY3JmT09CTUFFIDwtIGNyZk9PQk1BRSArIG1lYW4oYWJzKGNyZk1vZGVsT09CRXJyKSkNCiAgICBjcmZPT0JFcnJSMiA8LSBjcmZPT0JFcnJSMiArIGNvcihhcy5udW1lcmljKGFzLm1hdHJpeChjcmZNb2RlbE9PQikpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzLm51bWVyaWMoYXMubWF0cml4KGNyZk1vZGVsQGRhdGFAZW52JHJlc3BvbnNlW1tuYW1lcyhjcmZNb2RlbEBkYXRhQGVudiRyZXNwb25zZSldXSkpKV4yDQoNCiAgICAjIHNldCByYW5kb20gc2VlZA0KICAgIHNldC5zZWVkKHNlZWRzW2l0ZXJzXSkNCg0KICAgICMgc2V0IHJhbmRvbSBzZWVkDQogICAgc2V0LnNlZWQoc2VlZHNbaXRlcnNdKQ0KICAgICMgY29uZGl0aW9uYWwgdmFyaWFibGUgcGVybXV0YXRpb24gaW1wb3J0YW5jZQ0KICAgIGNyZkNvblBlcm1JbXAgPC0gcGVybWltcDo6cGVybWltcChjcmZNb2RlbCwgbnBlcm09bnBlcm0sIGNvbmRpdGlvbmFsPVRSVUUsIHRocmVzaG9sZD1wZXJtSW1wQ29uZFRocmVzLCBwcm9ncmVzc0Jhcj1GQUxTRSkNCiAgICANCiAgICBjcmZDb25QZXJtSW1wVmFscyA8LSBjcmZDb25QZXJtSW1wVmFscyArIGNyZkNvblBlcm1JbXAkdmFsdWVzDQogICAgY3JmQ29uUGVybUltcFZhbHNQZXJUcmVlIDwtIHJiaW5kKGNyZkNvblBlcm1JbXBWYWxzUGVyVHJlZSwgY3JmQ29uUGVybUltcCRwZXJUcmVlKQ0KICB9DQogIA0KICAjIGF2ZXJhZ2UgbWV0cmljcw0KICBjcmZPT0JFcnJBbGwgPC0gY3JmT09CRXJyQWxsL2xlbmd0aChzZWVkcykNCiAgY3JmT09CUk1TRSA8LSBjcmZPT0JSTVNFL2xlbmd0aChzZWVkcykNCiAgY3JmT09CTUFFIDwtIGNyZk9PQk1BRS9sZW5ndGgoc2VlZHMpDQogIGNyZk9PQkVyclIyIDwtIGNyZk9PQkVyclIyL2xlbmd0aChzZWVkcykNCiAgY3JmQ29uUGVybUltcFZhbHMgPC0gZGF0YS5mcmFtZShDb25kUGVybUltcD1zb3J0KGNyZkNvblBlcm1JbXBWYWxzL2xlbmd0aChzZWVkcyksIGRlY3JlYXNpbmc9VFJVRSkpDQogICNjcmZDb25QZXJtSW1wVmFsc01uIDwtIHNvcnQoY29sTWVhbnMoY3JmQ29uUGVybUltcFZhbHNQZXJUcmVlKSwgZGVjcmVhc2luZz1UUlVFKSAgIyBtZWFuIG9mIGNvbmRpdGlvbmFsIHZhcmlhYmxlIGltcG9ydGFuY2UgdmFsdWVzIHBlciB0cmVlIChzYW1lIGFzIGNyZkNvblBlcm1JbXBWYWxzKQ0KICBjcmZDb25QZXJtSW1wVmFsc1F0bCA8LSBkYXRhLmZyYW1lKGFwcGx5KGNyZkNvblBlcm1JbXBWYWxzUGVyVHJlZSwgMiwgcXVhbnRpbGUsIHByb2JzPWMoMC4yNSwgMC41MCwgMC43NSkpKQ0KICANCiAgcmVzdWx0c091dCA8LSBsaXN0KCdPT0JfUk1TRSc9Y3JmT09CUk1TRSwgJ09PQl9NQUUnPWNyZk9PQk1BRSwgJ1JzcXVhcmVkJz1jcmZPT0JFcnJSMiwgJ2NvbmRpdGlvbmFsX3Blcm1pbXAnPWNyZkNvblBlcm1JbXBWYWxzLCAgICAgICAgICAgICAgICAgICAgICAnY29uZGl0aW9uYWxfcGVybWltcF9wZXJUcmVlJz1jcmZDb25QZXJtSW1wVmFsc1BlclRyZWUsICdjb25kaXRpb25hbF9wZXJtaW1wX3F0bCc9Y3JmQ29uUGVybUltcFZhbHNRdGwpDQogIHJldHVybihyZXN1bHRzT3V0KQ0KfQ0KDQpgYGANCg0KIyMgQ29tcGFyaW5nIHJhbmtpbmdzIGZyb20gdHdvIHNlZWRzIA0KDQpgYGB7cn0NCg0KY3JmUmVnIDwtIGZ1bmN0aW9uKGRhdGFJbiwgaVZhcnMsIGRWYXIsIHNlZWRzLCBudHJlZSwgbXRyeSwgcGVybUltcENvbmRUaHJlcz0wLjk1LCBtaW5zcGxpdD0yMCwgbWluYnVja2V0PTcsIG5wZXJtPTEpew0KICAjIGluaXRpYWxpc2UgdmFyaWFibGVzDQogIGNyZk9PQkVyckFsbCA8LSAwDQogIGNyZk9PQlJNU0UgPC0gMA0KICBjcmZPT0JNQUUgPC0gMA0KICBjcmZPT0JFcnJSMiA8LSAwDQogIGNyZk1hclBlcm1JbXBWYWxzIDwtIDANCiAgY3JmQ29uUGVybUltcFZhbHMgPC0gMA0KICBjcmZNYXJQZXJtSW1wVmFsc1BlclRyZWUgPC0gZGF0YS5mcmFtZSgpDQogIGNyZkNvblBlcm1JbXBWYWxzUGVyVHJlZSA8LSBkYXRhLmZyYW1lKCkNCg0KICAjIGZvcm11bGEgZm9yIHJlZ3Jlc3Npb24NCiAgZm9ybVZhcnMgPC0gcmVmb3JtdWxhdGUoaVZhcnMsIGRWYXIpDQogIA0KICBmb3IgKGl0ZXJzIGluIDE6bGVuZ3RoKHNlZWRzKSl7DQogIA0KICAgICMgc2V0IHJhbmRvbSBzZWVkDQogICAgc2V0LnNlZWQoc2VlZHNbaXRlcnNdKQ0KICAgICMgdHJhaW4gY3JmIG1vZGVsDQogICAgY3JmTW9kZWwgPC0gcGFydHk6OmNmb3Jlc3QoZm9ybVZhcnMsIGRhdGE9ZGF0YUluLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyb2xzPXBhcnR5OjpjZm9yZXN0X3VuYmlhc2VkKG50cmVlPW50cmVlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG10cnk9bXRyeSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW5zcGxpdD1taW5zcGxpdCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW5idWNrZXQ9bWluYnVja2V0KSkNCiAgICANCiAgICAjIGNvbmRpdGlvbmFsIHZhcmlhYmxlIHBlcm11dGF0aW9uIGltcG9ydGFuY2UNCiAgICBjcmZDb25QZXJtSW1wIDwtIHBlcm1pbXA6OnBlcm1pbXAoY3JmTW9kZWwsIG5wZXJtPW5wZXJtLCBjb25kaXRpb25hbD1UUlVFLCB0aHJlc2hvbGQ9cGVybUltcENvbmRUaHJlcywgcHJvZ3Jlc3NCYXI9RkFMU0UpDQogICAgDQogICAgY3JmQ29uUGVybUltcFZhbHMgPC0gY3JmQ29uUGVybUltcCR2YWx1ZXMNCiAgICANCiAgICBpZiAoaXRlcnMgPT0gMSl7DQogICAgICBjcmZDb25QZXJtSW1wVmFsczEgPC0gZGF0YS5mcmFtZShDb25kUGVybUltcD1zb3J0KGNyZkNvblBlcm1JbXBWYWxzLCBkZWNyZWFzaW5nPVRSVUUpKQ0KICAgICAgY3JmQ29uUGVybUltcFZhbHNQZXJUcmVlMSA8LSBjcmZDb25QZXJtSW1wJHBlclRyZWUNCiAgICAgIGNyZkNvblBlcm1JbXBWYWxzUXRsMSA8LSBkYXRhLmZyYW1lKGFwcGx5KGNyZkNvblBlcm1JbXBWYWxzUGVyVHJlZTEsIDIsIHF1YW50aWxlLCBwcm9icz1jKDAuMjUsIDAuNTAsIDAuNzUpKSkNCiAgICAgIA0KICAgICAgIyBnZXQgT09CIHByZWRpY3Rpb25zDQogICAgICBjcmZNb2RlbE9PQiA8LSBwcmVkaWN0KGNyZk1vZGVsLCBPT0I9VFJVRSwgdHlwZT0ncmVzcG9uc2UnKQ0KICAgICAgDQogICAgICAjIGdldCBPT0IgZXJyb3INCiAgICAgIGNyZk1vZGVsT09CRXJyIDwtIGFzLm51bWVyaWMoYXMubWF0cml4KGFzLm51bWVyaWMoYXMubWF0cml4KGNyZk1vZGVsT09CKSkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAtIGFzLm51bWVyaWMoYXMubWF0cml4KGNyZk1vZGVsQGRhdGFAZW52JHJlc3BvbnNlW1tuYW1lcyhjcmZNb2RlbEBkYXRhQGVudiRyZXNwb25zZSldXSkpKSkNCiAgICAgIA0KICAgICAgIyBPT0IgUk1TRSwgZXJyb3IgcXVhcnRpbGVzIGFuZCBSc3F1YXJlZA0KICAgICAgY3JmT09CUk1TRSA8LSBzcXJ0KG1lYW4oY3JmTW9kZWxPT0JFcnJeMikpDQogICAgICBjcmZPT0JNQUUgPC0gY3JmT09CTUFFICsgbWVhbihhYnMoY3JmTW9kZWxPT0JFcnIpKQ0KICAgICAgY3JmT09CRXJyUjIgPC0gY29yKGFzLm51bWVyaWMoYXMubWF0cml4KGNyZk1vZGVsT09CKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcy5udW1lcmljKGFzLm1hdHJpeChjcmZNb2RlbEBkYXRhQGVudiRyZXNwb25zZVtbbmFtZXMoY3JmTW9kZWxAZGF0YUBlbnYkcmVzcG9uc2UpXV0pKSleMg0KDQogICAgICB9DQogICAgDQogICAgZWxzZXsNCiAgICAgIGNyZkNvblBlcm1JbXBWYWxzTiA8LSBkYXRhLmZyYW1lKENvbmRQZXJtSW1wPXNvcnQoY3JmQ29uUGVybUltcFZhbHMsIGRlY3JlYXNpbmc9VFJVRSkpDQogICAgICANCiAgICAgIG5WYXJJbXBDaGVja3MgPC0gbWluKG1heChzdW0oY3JmQ29uUGVybUltcFZhbHMxID49IGNyZkNvblBlcm1JbXBWYWxzMSRDb25kUGVybUltcFsxXSowLjEpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1bShjcmZDb25QZXJtSW1wVmFsc04gPj0gY3JmQ29uUGVybUltcFZhbHNOJENvbmRQZXJtSW1wWzFdKjAuMSkpLCA0KSAgIyBudW1iZXIgb2YgdmFyaWFibGUgaW1wb3J0YW5jZSB2YWx1ZXMgd2l0aCBhIHZhbHVlIGF0IGxlYXN0IDEwJSBvZiB0aGUgaGlnaGVzdCBpbXBvcnRhbmNlDQogICAgICBpZiAoc3VtKHJvd25hbWVzKGNyZkNvblBlcm1JbXBWYWxzMSlbMTpuVmFySW1wQ2hlY2tzXSAhPSByb3duYW1lcyhjcmZDb25QZXJtSW1wVmFsc04pWzE6blZhckltcENoZWNrc10pID4gMCl7DQogICAgICAgIHdhcm5pbmcoIlBlcm11dGF0aW9uIGltcG9ydGFuY2UgcmFuayBvcmRlciB3aXRoaW4gMTAlIG9mIG1heCBkaWZmZXJzIGJldHdlZW4gc2VlZHM6IGluY3JlYXNlIG51bWJlciBvZiB0cmVlcyAoJ250cmVlJykgb3IgbnVtYmVyIG9mIHBlcm11dGF0aW9ucyAoJ25wZXJtJyksIG9yIHN1YnNhbXBsZSBvZiBmZWF0dXJlcyAoJ210cnknKSIpDQogICAgICB9DQogICAgICBlbHNlew0KICAgICAgICByZXN1bHRzT3V0IDwtIGxpc3QoJ09PQl9lcnJvcnMnPWNyZk1vZGVsT09CRXJyLCAnT09CX1JNU0UnPWNyZk9PQlJNU0UsICdPT0JfTUFFJz1jcmZPT0JNQUUsICdSc3F1YXJlZCc9Y3JmT09CRXJyUjIsICdjb25kaXRpb25hbF9wZXJtaW1wJz1jcmZDb25QZXJtSW1wVmFsczEsICdjb25kaXRpb25hbF9wZXJtaW1wX3BlclRyZWUnPWNyZkNvblBlcm1JbXBWYWxzUGVyVHJlZTEsICdjb25kaXRpb25hbF9wZXJtcGltcF9xdGwnPWNyZkNvblBlcm1JbXBWYWxzUXRsMSkNCiAgICAgICAgcmV0dXJuKHJlc3VsdHNPdXQpDQogICAgICB9DQogICAgICANCiAgICB9DQogICAgDQogIH0NCg0KfQ0KDQpgYGANCg0KIyMgSHlwZXJwYXJhbWV0ZXIgdHVuaW5nDQoNCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NH0NCm10cnlUdW5lIDwtIGZ1bmN0aW9uKGRhdGFJbiwgaVZhcnMsIGRWYXIsIHNlZWQsIG50cmVlcywgbWluc3BsaXQ9MjAsIG1pbmJ1Y2tldD03KXsNCiAgDQogIGZvcm1WYXJzIDwtIHJlZm9ybXVsYXRlKGlWYXJzLCBkVmFyKQ0KICANCiAgIyBzZXQgbXRyeSB2YWx1ZXMgYW5kIGNvcnJlc3BvbmRpbmcgaVZhcnMvbXRyeSByYXRpb3MNCiAgaVZhcnNfbXRyeXMgPC0gYygxMC41LCA1LjI1LCAzLjUsIDIuNzUsIDIuMjUsIDEuNzUsIDEuNSwgMS4yNSkNCiAgbXRyeXMgPC0gYXMuaW50ZWdlcihsZW5ndGgoaVZhcnMpL2lWYXJzX210cnlzKQ0KICBpVmFyc19tdHJ5cyA8LSBpVmFyc19tdHJ5c1ttdHJ5cyA+PSAyXSAgIyByZW1vdmUgMCBvciAxIHZhbHVlcw0KICBtdHJ5cyA8LSBtdHJ5c1ttdHJ5cyA+PSAyXSAgIyByZW1vdmUgMCBvciAxIHZhbHVlcw0KICANCiAgIyByZW1vdmUgYW55IGR1cGxpY2F0ZWQgdmFsdWVzDQogIGlWYXJzX210cnlzIDwtIGlWYXJzX210cnlzWyEoZHVwbGljYXRlZChtdHJ5cykgfCBkdXBsaWNhdGVkKG10cnlzLCBmcm9tTGFzdCA9IFRSVUUpKV0NCiAgbXRyeXMgPC0gbXRyeXNbIShkdXBsaWNhdGVkKG10cnlzKSB8IGR1cGxpY2F0ZWQobXRyeXMsIGZyb21MYXN0ID0gVFJVRSkpXQ0KDQogICMgZW5zdXJlIG10cnlzIGlzIGxlc3MgdGhhbiBsZW5ndGgoaVZhcnMpDQogIGlWYXJzX210cnlzIDwtIGlWYXJzX210cnlzW210cnlzIDwgbGVuZ3RoKGlWYXJzKV0NCiAgbXRyeXMgPC0gbXRyeXNbbXRyeXMgPCBsZW5ndGgoaVZhcnMpXQ0KDQogIHJlc1JNU0VNYXAgPSBtYXRyaXgoZGF0YT1OQSwgbnJvdz1sZW5ndGgobXRyeXMpLCBuY29sPWxlbmd0aChudHJlZXMpKQ0KICByZXNSc3F1YXJlZE1hcCA9IG1hdHJpeChkYXRhPU5BLCBucm93PWxlbmd0aChtdHJ5cyksIG5jb2w9bGVuZ3RoKG50cmVlcykpDQogIHJlc01BRU1hcCA9IG1hdHJpeChkYXRhPU5BLCBucm93PWxlbmd0aChtdHJ5cyksIG5jb2w9bGVuZ3RoKG50cmVlcykpDQogIA0KICBmb3IgKGlpIGluIHNlcSgxLCBsZW5ndGgobnRyZWVzKSkpew0KICAgIHNldC5zZWVkKHNlZWQpDQogICAgbnRyZWUgPSBudHJlZXNbaWldDQogICAgdHVuZU1vZCA8LSBjYXJldDo6dHJhaW4oZm9ybVZhcnMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YT1kYXRhSW4sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kPSdjZm9yZXN0JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250cm9scz1wYXJ0eTo6Y2ZvcmVzdF91bmJpYXNlZChudHJlZT1udHJlZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW5zcGxpdD1taW5zcGxpdCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW5idWNrZXQ9bWluYnVja2V0KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0dW5lR3JpZD1kYXRhLmZyYW1lKC5tdHJ5PW10cnlzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ckNvbnRyb2wgPSB0cmFpbkNvbnRyb2wobWV0aG9kID0gIm9vYiIpKQ0KICAgIA0KICAgIHR1bmVNb2QkcmVzdWx0cyA8LSBjYmluZCh0dW5lTW9kJHJlc3VsdHMsIGRhdGEuZnJhbWUoaVZhcnNfbXRyeXM9aVZhcnNfbXRyeXMpKQ0KICAgIA0KICAgIHByaW50KHR1bmVNb2QkcmVzdWx0cykNCiAgICBwcmludCh0dW5lTW9kJGJlc3RUdW5lKQ0KICAgIA0KICAgIHJlc1JNU0VNYXBbLCBpaV0gPSB0dW5lTW9kJHJlc3VsdHMkUk1TRQ0KICAgIHJlc1JzcXVhcmVkTWFwWywgaWldID0gdHVuZU1vZCRyZXN1bHRzJFJzcXVhcmVkDQogICAgcmVzTUFFTWFwWywgaWldID0gdHVuZU1vZCRyZXN1bHRzJE1BRQ0KICAgIA0KICB9DQogIA0KICANCiAgIyBjb252ZXJ0IHRvIGRhdGEgZnJhbWVzIHdpdGggbXRyeSBhcyByb3cgbmFtZXMgYW5kIG50cmVlIGFzIGNvbHVtbiBuYW1lcywgYW5kIGNvbnZlcnQgdG8gbG9uZyBmb3JtYXQgdXNpbmcgdGlkeXZlcnNlDQogIHJlc2RmUk1TRU1hcCA8LSBhcy5kYXRhLmZyYW1lKHJlc1JNU0VNYXApDQogIHJvd25hbWVzKHJlc2RmUk1TRU1hcCkgPC0gbXRyeXMNCiAgY29sbmFtZXMocmVzZGZSTVNFTWFwKSA8LSBudHJlZXMNCiAgcmVzZGZSc3F1YXJlZE1hcCA8LSBhcy5kYXRhLmZyYW1lKHJlc1JzcXVhcmVkTWFwKQ0KICByb3duYW1lcyhyZXNkZlJzcXVhcmVkTWFwKSA8LSBtdHJ5cw0KICBjb2xuYW1lcyhyZXNkZlJzcXVhcmVkTWFwKSA8LSBudHJlZXMNCiAgcmVzZGZNQUVNYXAgPC0gYXMuZGF0YS5mcmFtZShyZXNNQUVNYXApDQogIHJvd25hbWVzKHJlc2RmTUFFTWFwKSA8LSBtdHJ5cw0KICBjb2xuYW1lcyhyZXNkZk1BRU1hcCkgPC0gbnRyZWVzDQogIA0KICANCiAgIyBjb252ZXJ0IGRhdGFmcmFtZXMgdG8gbG9uZyBmb3JtYXQgdXNpbmcgdGlkeXZlcnNlDQogIHJlc2RmUk1TRU1hcCA8LSByZXNkZlJNU0VNYXAgfD4NCiAgICAgICAgICAgICAgICAgICAgICByb3duYW1lc190b19jb2x1bW4oJ210cnknKSB8Pg0KICAgICAgICAgICAgICAgICAgICAgICAgICBnYXRoZXIoa2V5PSdudHJlZScsIHZhbHVlPSdSTVNFJywgLW10cnkpDQogIA0KICByZXNkZlJzcXVhcmVkTWFwIDwtIHJlc2RmUnNxdWFyZWRNYXAgfD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgcm93bmFtZXNfdG9fY29sdW1uKCdtdHJ5JykgfD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdhdGhlcihrZXk9J250cmVlJywgdmFsdWU9J1JzcXVhcmVkJywgLW10cnkpDQogIA0KICByZXNkZk1BRU1hcCA8LSByZXNkZk1BRU1hcCB8Pg0KICAgICAgICAgICAgICAgICAgICByb3duYW1lc190b19jb2x1bW4oJ210cnknKSB8Pg0KICAgICAgICAgICAgICAgICAgICAgICAgZ2F0aGVyKGtleT0nbnRyZWUnLCB2YWx1ZT0nTUFFJywgLW10cnkpDQogIA0KICAjIGVuc3VyZSBudHJlZSBhbmQgbXRyeSBjb2x1bW5zIGFyZSBvcmRlcmVkIGZhY3RvcnMNCiAgcmVzZGZSTVNFTWFwJG50cmVlIDwtIGZhY3RvcihyZXNkZlJNU0VNYXAkbnRyZWUsIGxldmVscz1hcy5jaGFyYWN0ZXIobnRyZWVzKSkNCiAgcmVzZGZSTVNFTWFwJG10cnkgPC0gZmFjdG9yKHJlc2RmUk1TRU1hcCRtdHJ5LCBsZXZlbHM9YXMuY2hhcmFjdGVyKG10cnlzKSkNCiAgDQogIHJlc2RmUnNxdWFyZWRNYXAkbnRyZWUgPC0gZmFjdG9yKHJlc2RmUnNxdWFyZWRNYXAkbnRyZWUsIGxldmVscz1hcy5jaGFyYWN0ZXIobnRyZWVzKSkNCiAgcmVzZGZSc3F1YXJlZE1hcCRtdHJ5IDwtIGZhY3RvcihyZXNkZlJzcXVhcmVkTWFwJG10cnksIGxldmVscz1hcy5jaGFyYWN0ZXIobXRyeXMpKQ0KICANCiAgcmVzZGZNQUVNYXAkbnRyZWUgPC0gZmFjdG9yKHJlc2RmTUFFTWFwJG50cmVlLCBsZXZlbHM9YXMuY2hhcmFjdGVyKG50cmVlcykpDQogIHJlc2RmTUFFTWFwJG10cnkgPC0gZmFjdG9yKHJlc2RmTUFFTWFwJG10cnksIGxldmVscz1hcy5jaGFyYWN0ZXIobXRyeXMpKQ0KICANCiAgIyBwbG90IGhlYXRtYXBzIHVzaW5nIGdncGxvdCwgd2l0aCBleHRyZW1lIChtaW4gb3IgbWF4KSB2YWx1ZSBwbG90dGVkIGFzIG92ZXJsYWlkIHBvaW50IHVzaW5nIGFubm90YXRlIGFuZCBjb2xvdXJiYXIgc2NhbGUgcmV2ZXJzZWQNCiAgcEhlYXRtYXBSTVNFIDwtIGdncGxvdChyZXNkZlJNU0VNYXApICsNCiAgICAgICAgICAgICAgICAgICAgZ2VvbV90aWxlKGFlcyh4PW50cmVlLCB5PW10cnksIGZpbGw9Uk1TRSkpICsNCiAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2ZpbGxfdmlyaWRpcyhvcHRpb249InZpcmlkaXMiLCBkaXJlY3Rpb249LTEpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9wb2ludChkYXRhPXJlc2RmUk1TRU1hcFt3aGljaChyZXNkZlJNU0VNYXAkUk1TRQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID09IG1pbihyZXNkZlJNU0VNYXAkUk1TRSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXJyLmluZCA9IFRSVUUpLF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKHg9bnRyZWUsIHk9bXRyeSksIGNvbG91cj0icmVkIiwgc2l6ZT0yKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2NvbG91cmJhcihyZXZlcnNlPVRSVUUpKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJzKHg9Im50cmVlIiwgeT0ibXRyeSIsIGZpbGw9IlJNU0UiKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIikpDQogIA0KICBwSGVhdG1hcFJzcXVhcmVkIDwtIGdncGxvdChyZXNkZlJzcXVhcmVkTWFwKSArDQogICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3RpbGUoYWVzKHg9bnRyZWUsIHk9bXRyeSwgZmlsbD1Sc3F1YXJlZCkpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9maWxsX3ZpcmlkaXMob3B0aW9uPSJ2aXJpZGlzIiwgZGlyZWN0aW9uPTEpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcG9pbnQoZGF0YT1yZXNkZlJzcXVhcmVkTWFwW3doaWNoKHJlc2RmUnNxdWFyZWRNYXAkUnNxdWFyZWQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID09IG1heChyZXNkZlJzcXVhcmVkTWFwJFJzcXVhcmVkKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFyci5pbmQgPSBUUlVFKSxdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZXMoeD1udHJlZSwgeT1tdHJ5KSwgY29sb3VyPSJyZWQiLCBzaXplPTIpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2NvbG91cmJhcihyZXZlcnNlPVRSVUUpKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFicyh4PSJudHJlZSIsIHk9Im10cnkiLCBmaWxsPSJSc3F1YXJlZCIpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIikpDQogIA0KICBwSGVhdG1hcE1BRSA8LSBnZ3Bsb3QocmVzZGZNQUVNYXApICsNCiAgICAgICAgICAgICAgICAgICAgZ2VvbV90aWxlKGFlcyh4PW50cmVlLCB5PW10cnksIGZpbGw9TUFFKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfZmlsbF92aXJpZGlzKG9wdGlvbj0idmlyaWRpcyIsIGRpcmVjdGlvbj0tMSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3BvaW50KGRhdGE9cmVzZGZNQUVNYXBbd2hpY2gocmVzZGZNQUVNYXAkTUFFDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA9PSBtaW4ocmVzZGZNQUVNYXAkTUFFKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFyci5pbmQgPSBUUlVFKSxdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFlcyh4PW50cmVlLCB5PW10cnkpLCBjb2xvdXI9InJlZCIsIHNpemU9MikgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9jb2xvdXJiYXIocmV2ZXJzZT1UUlVFKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFicyh4PSJudHJlZSIsIHk9Im10cnkiLCBmaWxsPSJNQUUiKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIikpDQogIA0KICBwIDwtICBjb3dwbG90OjpwbG90X2dyaWQocEhlYXRtYXBSTVNFLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgcEhlYXRtYXBSc3F1YXJlZCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBIZWF0bWFwTUFFLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgbmNvbD0zLCBucm93PTEpDQogIA0KICByZXR1cm4ocCkNCiAgDQp9ICAjIGVuZCBvZiBmdW5jdGlvbg0KDQpgYGANCg0KDQojIFBhcnQgQSBhbmFseXNpcw0KDQoNCiMjIFNldCBnbG9iYWwgcGFyYW1ldGVycw0KDQpgYGB7cn0NCg0KcGVybUltcENvbmRUaHJlcyA8LSAwLjk1DQptaW5zcGxpdCA8LSAyMA0KbWluYnVja2V0IDwtIDcNCm50cmVlcyA8LSBjKDI1MSwgNTAxLCAxMDAxLCAxNTAxLCAyNTAxLCA0MDAxLCA1NTAxKQ0KDQpgYGANCg0KIyMgTWVhbiBjaGFuZ2UgaW4gYW5ub3lhbmNlDQoNCkluaXRpYWxpc2UgcmVzdWx0cyBvdXRwdXQgdmFyaWFibGVzDQoNCmBgYHtyfQ0KcmVzZEFubm95TW5GaXQgPC0gZGF0YS5mcmFtZShSTVNFID0gbnVtZXJpYygpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBNQUUgPSBudW1lcmljKCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIFJzcXVhcmVkID0gbnVtZXJpYygpKQ0KcmVzZEFubm95TW5QZXJtSW1wIDwtIGxpc3QoKQ0KDQpgYGANCg0KDQojIyMgQWxsIHZhcmlhYmxlcyAoYWJzb2x1dGUgYW5kIGRpZmZlcmVuY2UpDQoNCiMjIyMgUmVtb3ZlIGFtYmllbnQgb25seSBzdGltdWxpDQoNCkhlcmUsIHRoZSAnYW1iaWVudCBvbmx5JyBzdGltdWxpIGFyZSByZW1vdmVkLCBhcyB0aGUgYW5hbHlzaXMgY2Fubm90IGhhbmRsZSBtaXNzaW5nIHZhbHVlcyBmb3IgZEIgbWV0cmljcy4NCg0KYGBge3J9DQpzdGltRGF0YUFOdW0gPC0gc3RpbURhdGFBTnVtW2NvbXBsZXRlLmNhc2VzKHN0aW1EYXRhQU51bSksXQ0Kc3RpbURhdGFBTnVtJFVBU0xBZXEgPC0gYXMubnVtZXJpYyhzdGltRGF0YUFOdW0kVUFTTEFlcSkNCnN0aW1EYXRhQU51bSRTTlJsZXZlbCA8LSBhcy5udW1lcmljKHN0aW1EYXRhQU51bSRTTlJsZXZlbCkNCmBgYA0KDQojIyMjIFNldCB2YXJpYWJsZXMNCg0KYGBge3J9DQoNCmlWYXJzIDwtIG5hbWVzKHN0aW1EYXRhQU51bSlbd2hpY2gobmFtZXMoc3RpbURhdGFBTnVtKSA9PSAnVUFTTEFlcScpOndoaWNoKG5hbWVzKHN0aW1EYXRhQU51bSkgPT0gJ1VBU0ltcHVsc1NITTA1RXhNYXhMUicpXQ0KaVZhcnMgPC0gaVZhcnNbISBpVmFycyAlaW4lICdTTlJsZXZlbCddDQppVmFycyA8LSBjKGlWYXJzLA0KICAgICAgICAgICBuYW1lcyhzdGltRGF0YUFOdW0pW3doaWNoKGNvbG5hbWVzKHN0aW1EYXRhQU51bSk9PSJMQWVxTEFGOTBkaWZmIik6DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2hpY2goY29sbmFtZXMoc3RpbURhdGFBTnVtKT09ImRJbXB1bHNTSE0wNUV4TWF4TFIiKV0sICJTTlJsZXZlbCIpDQpkVmFyIDwtICJkQW5ub3lNZWFuIg0KDQpzZWVkcyA8LSBjKDE0NTY5LCA5ODY1MSwgNTQ2NTQ0OTgsIDQ1NDk0OCwgNDEzMjEpDQoNCmBgYA0KDQojIyMjIEh5cGVycGFyYW1ldGVyIHR1bmluZw0KDQpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTR9DQoNCnAgPC0gbXRyeVR1bmUoZGF0YUluPXN0aW1EYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZD1zZWVkc1sxXSwNCiAgICAgICAgICAgICAgbnRyZWVzPW50cmVlcywgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQpwDQppZiAoc2F2ZXBsb3RzKXsNCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFkQW5ub3lNbkFsbFZhcnNIeXBlclR1bmUuc3ZnIiwgd2lkdGg9MTIsIGhlaWdodD00LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAic3ZnIikpDQogIHVubGluaygiUHRBZEFubm95TW5BbGxWYXJzSHlwZXJUdW5lLnN2ZyIpDQoNCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFkQW5ub3lNbkFsbFZhcnNIeXBlclR1bmUucGRmIiwgd2lkdGg9MTIsIGhlaWdodD00LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAicGRmIikpDQogIHVubGluaygiUHRBZEFubm95TW5BbGxWYXJzSHlwZXJUdW5lLnBkZiIpDQp9DQoNCmBgYA0KDQpTZWxlY3RlZCBoeXBlcnBhcmFtZXRlcnMNCg0KYGBge3J9DQoNCm50cmVlIDwtIDI1MQ0KbXRyeSA8LSBhcy5pbnRlZ2VyKGxlbmd0aChpVmFycykvMS41KQ0KDQpgYGANCg0KIyMjIyBSdW4gbW9kZWwNCg0KVHJhaW4gcHJlbGltaW5hcnkgbW9kZWwNCg0KYGBge3J9DQoNCm5wZXJtIDwtIDEwDQoNCnJlc3VsdHNPdXRBYnNEaWZmcyA8LSBjcmZSZWcoZGF0YUluPXN0aW1EYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHNbMToyXSwgbnRyZWU9bnRyZWUsIG10cnk9bXRyeSwgcGVybUltcENvbmRUaHJlcz1wZXJtSW1wQ29uZFRocmVzLCBucGVybT1ucGVybSwgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQoNCiMgcHJpbnQgbW9kZWwgcHJlZGljdGlvbiByZXN1bHRzDQpyZXN1bHRzT3V0QWJzRGlmZnMkT09CX1JNU0UNCnJlc3VsdHNPdXRBYnNEaWZmcyRPT0JfTUFFDQpyZXN1bHRzT3V0QWJzRGlmZnMkUnNxdWFyZWQNCg0KYGBgDQoNClRyYWluIG11bHRpcGxlIHNlZWRzIG1vZGVsDQoNCmBgYHtyfQ0KDQpyZXN1bHRzT3V0QWJzRGlmZnMgPC0gbXVsdGlfY3JmUmVnKGRhdGFJbj1zdGltRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzLCBudHJlZT1udHJlZSwgbXRyeT1tdHJ5LCBwZXJtSW1wQ29uZFRocmVzPXBlcm1JbXBDb25kVGhyZXMsIG5wZXJtPW5wZXJtLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCg0KIyBwcmludCBtb2RlbCBwcmVkaWN0aW9uIHJlc3VsdHMNCnJlc3VsdHNPdXRBYnNEaWZmcyRPT0JfUk1TRQ0KcmVzdWx0c091dEFic0RpZmZzJE9PQl9NQUUNCnJlc3VsdHNPdXRBYnNEaWZmcyRSc3F1YXJlZA0KYGBgDQoNCmBgYHtyfQ0KIyBzdG9yZSByZXN1bHRzDQpyZXNkQW5ub3lNbkZpdFsnQWxsIHZhcnMnLCAnUk1TRSddIDwtIHJlc3VsdHNPdXRBYnNEaWZmcyRPT0JfUk1TRQ0KcmVzZEFubm95TW5GaXRbJ0FsbCB2YXJzJywgJ01BRSddIDwtIHJlc3VsdHNPdXRBYnNEaWZmcyRPT0JfTUFFDQpyZXNkQW5ub3lNbkZpdFsnQWxsIHZhcnMnLCAnUnNxdWFyZWQnXSA8LSByZXN1bHRzT3V0QWJzRGlmZnMkUnNxdWFyZWQNCnJlc2RBbm5veU1uUGVybUltcCRBbGxWYXJzIDwtIHJlc3VsdHNPdXRBYnNEaWZmcyRjb25kaXRpb25hbF9wZXJtaW1wDQoNCmBgYA0KDQojIyMjIFBsb3QgcmVzdWx0cw0KDQpgYGB7ciwgZmlnLndpZHRoPTgsZmlnLmhlaWdodD0yMH0NCnBhcihtYWk9YygwLDMsMCwwKSkNCg0KIyBwbG90IGNvbmRpdGlvbmFsIGltcG9ydGFuY2UNCnJlc3VsdHNPdXRBYnNEaWZmcy5jb25pbXAgPC0gYXJyYW5nZShyZXN1bHRzT3V0QWJzRGlmZnMkY29uZGl0aW9uYWxfcGVybWltcCwgZGVzYyhyb3dfbnVtYmVyKCkpKQ0KDQpwQmFyIDwtIGdncGxvdChyZXN1bHRzT3V0QWJzRGlmZnMuY29uaW1wKSArIGdlb21fY29sKGFlcyh4PWZhY3Rvcihyb3duYW1lcyhyZXN1bHRzT3V0QWJzRGlmZnMuY29uaW1wKSwgbGV2ZWxzPXJvd25hbWVzKHJlc3VsdHNPdXRBYnNEaWZmcy5jb25pbXApKSwgeT1Db25kUGVybUltcCksIGZpbGw9bXljb2xvdXJzWzldLCB3aWR0aD0wLjUpICsgbGFicyh4PSJWYXJpYWJsZSIsIHk9IkNvbmRpdGlvbmFsIHZhcmlhYmxlIHBlcm11dGF0aW9uIGltcG9ydGFuY2UgKG1lYW4gY2hhbmdlIGluIGFubm95YW5jZSkiKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiksIHBhbmVsLmdyaWQ9ZWxlbWVudF9saW5lKGNvbG9yID0gcmdiKDIzNSwgMjM1LCAyMzUsIDEwMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksIGxpbmV3aWR0aCA9IDAuMjUsIGxpbmV0eXBlID0gMikpICsgY29vcmRfZmxpcCgpDQpwQmFyDQoNCmlmIChzYXZlcGxvdHMpew0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWRBbm5veU1uQWxsVmFyc0NvblBlcm1pbXAuc3ZnIiwgd2lkdGg9OCwgaGVpZ2h0PTIwLCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAic3ZnIikpDQogIHVubGluaygiUHRBZEFubm95TW5BbGxWYXJzQ29uUGVybWltcC5zdmciKQ0KDQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBZEFubm95TW5BbGxWYXJzQ29uUGVybWltcC5wZGYiLCB3aWR0aD04LCBoZWlnaHQ9MjAsIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJwZGYiKSkNCiAgdW5saW5rKCJQdEFkQW5ub3lNbkFsbFZhcnNDb25QZXJtaW1wLnBkZiIpDQp9DQoNCmBgYA0KDQpgYGB7ciwgZmlnLndpZHRoPTgsZmlnLmhlaWdodD04fQ0KDQojIFBsb3Qgb25seSBwb3NpdGl2ZSB2YWx1ZXMNCg0KcmVzdWx0c091dEFic0RpZmZzLmNvbmltcFB0diA8LSByZXN1bHRzT3V0QWJzRGlmZnMuY29uaW1wIHw+DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3duYW1lc190b19jb2x1bW4oJ01ldHJpYycpIHw+DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXJfaWYoaXMubnVtZXJpYywgYWxsX3ZhcnMoLiA+IDApKSB8Pg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sdW1uX3RvX3Jvd25hbWVzKCdNZXRyaWMnKQ0KDQpwQmFyIDwtIGdncGxvdChyZXN1bHRzT3V0QWJzRGlmZnMuY29uaW1wUHR2KSArIGdlb21fY29sKGFlcyh4PWZhY3Rvcihyb3duYW1lcyhyZXN1bHRzT3V0QWJzRGlmZnMuY29uaW1wUHR2KSwgbGV2ZWxzPXJvd25hbWVzKHJlc3VsdHNPdXRBYnNEaWZmcy5jb25pbXBQdHYpKSwgeT1Db25kUGVybUltcCksIGZpbGw9bXljb2xvdXJzWzldLCB3aWR0aD0wLjUpICsgbGFicyh4PSJWYXJpYWJsZSIsIHk9IkNvbmRpdGlvbmFsIHZhcmlhYmxlIHBlcm11dGF0aW9uIGltcG9ydGFuY2UgKG1lYW4gY2hhbmdlIGluIGFubm95YW5jZSkiKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiksIHBhbmVsLmdyaWQ9ZWxlbWVudF9saW5lKGNvbG9yID0gcmdiKDIzNSwgMjM1LCAyMzUsIDEwMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksIGxpbmV3aWR0aCA9IDAuMjUsIGxpbmV0eXBlID0gMikpICsgY29vcmRfZmxpcCgpDQpwQmFyDQoNCmlmIChzYXZlcGxvdHMpew0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWRBbm5veU1uQWxsVmFyc0NvblBlcm1pbXBQdHYuc3ZnIiwgd2lkdGg9OCwgaGVpZ2h0PTgsIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJzdmciKSkNCiAgdW5saW5rKCJQdEFkQW5ub3lNbkFsbFZhcnNDb25QZXJtaW1wLnN2ZyIpDQogIA0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWRBbm5veU1uQWxsVmFyc0NvblBlcm1pbXBQdHYucGRmIiwgd2lkdGg9OCwgaGVpZ2h0PTgsIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJwZGYiKSkNCiAgdW5saW5rKCJQdEFkQW5ub3lNbkFsbFZhcnNDb25QZXJtaW1wLnBkZiIpDQp9DQoNCmBgYA0KDQojIyMgQWJzb2x1dGUgdmFyaWFibGVzDQoNCiMjIyMgU2V0IHZhcmlhYmxlcw0KDQpgYGB7cn0NCg0KaVZhcnMgPC0gbmFtZXMoc3RpbURhdGFBTnVtKVt3aGljaChuYW1lcyhzdGltRGF0YUFOdW0pID09ICdVQVNMQWVxJyk6d2hpY2gobmFtZXMoc3RpbURhdGFBTnVtKSA9PSAnVUFTSW1wdWxzU0hNMDVFeE1heExSJyldDQppVmFycyA8LSBpVmFyc1shIGlWYXJzICVpbiUgYygnU05SbGV2ZWwnKV0NCmRWYXIgPC0gImRBbm5veU1lYW4iDQoNCnNlZWRzIDwtIGMoNTc4MzEyLCA1NDQsIDg0ODk0LCA1NDY1NCwgMTUzMTU3KQ0KDQpgYGANCg0KIyMjIyBIeXBlcnBhcmFtZXRlciB0dW5pbmcNCg0KYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD00fQ0KDQpwIDwtIG10cnlUdW5lKGRhdGFJbj1zdGltRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWQ9c2VlZHNbMV0sDQogICAgICAgICAgICAgIG50cmVlcz1udHJlZXMsIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KcA0KDQppZiAoc2F2ZXBsb3RzKXsNCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFkQW5ub3lNbkFic1ZhcnNIeXBlclR1bmUuc3ZnIiwgd2lkdGg9MTIsIGhlaWdodD00LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAic3ZnIikpDQogIHVubGluaygiUHRBZEFubm95TW5BYnNWYXJzSHlwZXJUdW5lLnN2ZyIpDQoNCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFkQW5ub3lNbkFic1ZhcnNIeXBlclR1bmUucGRmIiwgd2lkdGg9MTIsIGhlaWdodD00LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAicGRmIikpDQogIHVubGluaygiUHRBZEFubm95TW5BYnNWYXJzSHlwZXJUdW5lLnBkZiIpDQp9DQoNCmBgYA0KDQpTZWxlY3RlZCBoeXBlcnBhcmFtZXRlcnMNCg0KYGBge3J9DQoNCm50cmVlIDwtIDE1MDENCm10cnkgPC0gYXMuaW50ZWdlcihsZW5ndGgoaVZhcnMpLzEuMjUpDQoNCmBgYA0KDQojIyMjIFJ1biBtb2RlbA0KDQpUcmFpbiBwcmVsaW1pbmFyeSBtb2RlbA0KDQpgYGB7cn0NCg0KbnBlcm0gPC0gNQ0KDQpyZXN1bHRzT3V0QWJzIDwtIGNyZlJlZyhkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkc1sxOjJdLCBudHJlZT1udHJlZSwgbXRyeT1tdHJ5LCBwZXJtSW1wQ29uZFRocmVzPXBlcm1JbXBDb25kVGhyZXMsIG5wZXJtPW5wZXJtLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCg0KIyBwcmludCBtb2RlbCBwcmVkaWN0aW9uIHJlc3VsdHMNCnJlc3VsdHNPdXRBYnMkT09CX1JNU0UNCnJlc3VsdHNPdXRBYnMkT09CX01BRQ0KcmVzdWx0c091dEFicyRSc3F1YXJlZA0KDQpgYGANClRyYWluIG11bHRpcGxlIHNlZWRzIG1vZGVsDQoNCmBgYHtyfQ0KDQpyZXN1bHRzT3V0QWJzIDwtIG11bHRpX2NyZlJlZyhkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkcywgbnRyZWU9bnRyZWUsIG10cnk9bXRyeSwgcGVybUltcENvbmRUaHJlcz1wZXJtSW1wQ29uZFRocmVzLCBucGVybT1ucGVybSwgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQoNCiMgcHJpbnQgbW9kZWwgcHJlZGljdGlvbiByZXN1bHRzDQpyZXN1bHRzT3V0QWJzJE9PQl9STVNFDQpyZXN1bHRzT3V0QWJzJE9PQl9NQUUNCnJlc3VsdHNPdXRBYnMkUnNxdWFyZWQNCg0KYGBgDQoNCg0KYGBge3J9DQoNCiMgc3RvcmUgcmVzdWx0cw0KcmVzZEFubm95TW5GaXRbJ0FicyB2YXJzJywgJ1JNU0UnXSA8LSByZXN1bHRzT3V0QWJzJE9PQl9STVNFDQpyZXNkQW5ub3lNbkZpdFsnQWJzIHZhcnMnLCAnTUFFJ10gPC0gcmVzdWx0c091dEFicyRPT0JfTUFFDQpyZXNkQW5ub3lNbkZpdFsnQWJzIHZhcnMnLCAnUnNxdWFyZWQnXSA8LSByZXN1bHRzT3V0QWJzJFJzcXVhcmVkDQpyZXNkQW5ub3lNblBlcm1JbXAkQWJzVmFycyA8LSByZXN1bHRzT3V0QWJzJGNvbmRpdGlvbmFsX3Blcm1pbXANCg0KYGBgDQoNCiMjIyMgUGxvdCByZXN1bHRzDQoNCmBgYHtyLCBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTExLjV9DQpwYXIobWFpPWMoMCwzLDAsMCkpDQoNCiMgcGxvdCBjb25kaXRpb25hbCBpbXBvcnRhbmNlDQpyZXN1bHRzT3V0QWJzLmNvbmltcCA8LSBhcnJhbmdlKHJlc3VsdHNPdXRBYnMkY29uZGl0aW9uYWxfcGVybWltcCwgZGVzYyhyb3dfbnVtYmVyKCkpKQ0KDQpwQmFyIDwtIGdncGxvdChyZXN1bHRzT3V0QWJzLmNvbmltcCkgKyBnZW9tX2NvbChhZXMoeD1mYWN0b3Iocm93bmFtZXMocmVzdWx0c091dEFicy5jb25pbXApLCBsZXZlbHM9cm93bmFtZXMocmVzdWx0c091dEFicy5jb25pbXApKSwgeT1Db25kUGVybUltcCksIGZpbGw9bXljb2xvdXJzWzFdLCB3aWR0aD0wLjUpICsgbGFicyh4PSJWYXJpYWJsZSIsIHk9IkNvbmRpdGlvbmFsIHZhcmlhYmxlIHBlcm11dGF0aW9uIGltcG9ydGFuY2UgKG1lYW4gY2hhbmdlIGluIGFubm95YW5jZSkiKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiksIHBhbmVsLmdyaWQ9ZWxlbWVudF9saW5lKGNvbG9yID0gcmdiKDIzNSwgMjM1LCAyMzUsIDEwMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksIGxpbmV3aWR0aCA9IDAuMjUsIGxpbmV0eXBlID0gMikpICsNCiAgY29vcmRfZmxpcCgpDQpwQmFyDQoNCmlmIChzYXZlcGxvdHMpew0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWRBbm5veU1uQWJzVmFyc0NvblBlcm1pbXAuc3ZnIiwgd2lkdGg9OCwgaGVpZ2h0PTExLjUsIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJzdmciKSkNCiAgdW5saW5rKCJQdEFkQW5ub3lNbkFic1ZhcnNDb25QZXJtaW1wLnN2ZyIpDQogIA0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWRBbm5veU1uQWJzVmFyc0NvblBlcm1pbXAucGRmIiwgd2lkdGg9OCwgaGVpZ2h0PTExLjUsIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJwZGYiKSkNCiAgdW5saW5rKCJQdEFkQW5ub3lNbkFic1ZhcnNDb25QZXJtaW1wLnBkZiIpDQp9DQpgYGANCg0KYGBge3IsIGZpZy53aWR0aD04LGZpZy5oZWlnaHQ9MTEuNX0NCg0KIyBQbG90IHZhbHVlcyBkaXNyZWdhcmRpbmcgYW1iaWVudCBMQWVxDQoNCnBCYXIgPC0gZ2dwbG90KHNsaWNlKHJlc3VsdHNPdXRBYnMuY29uaW1wLCAxOm4oKS0xKSkgKyBnZW9tX2NvbChhZXMoeD1mYWN0b3Iocm93bmFtZXMoc2xpY2UocmVzdWx0c091dEFicy5jb25pbXAsIDE6bigpLTEpKSwgbGV2ZWxzPXJvd25hbWVzKHNsaWNlKHJlc3VsdHNPdXRBYnMuY29uaW1wLCAxOm4oKS0xKSkpLCB5PUNvbmRQZXJtSW1wKSwgZmlsbD1teWNvbG91cnNbMV0sIHdpZHRoPTAuNSkgKyBsYWJzKHg9IlZhcmlhYmxlIiwgeT0iQ29uZGl0aW9uYWwgdmFyaWFibGUgcGVybXV0YXRpb24gaW1wb3J0YW5jZSAobWVhbiBjaGFuZ2UgaW4gYW5ub3lhbmNlKSIpICsgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2VyaWYiKSwgcGFuZWwuZ3JpZD1lbGVtZW50X2xpbmUoY29sb3IgPSByZ2IoMjM1LCAyMzUsIDIzNSwgMTAwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgbGluZXdpZHRoID0gMC4yNSwgbGluZXR5cGUgPSAyKSkgKyBjb29yZF9mbGlwKCkNCnBCYXINCg0KaWYgKHNhdmVwbG90cyl7DQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBZEFubm95TW5BYnNWYXJzU2tpcEFtYkNvblBlcm1pbXAuc3ZnIiwgd2lkdGg9OCwgaGVpZ2h0PTExLjUsIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJzdmciKSkNCiAgdW5saW5rKCJQdEFkQW5ub3lNbkFic1ZhcnNTa2lwQW1iQ29uUGVybWltcC5zdmciKQ0KICANCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFkQW5ub3lNbkFic1ZhcnNTa2lwQW1iQ29uUGVybWltcC5wZGYiLCB3aWR0aD04LCBoZWlnaHQ9MTEuNSwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInBkZiIpKQ0KICB1bmxpbmsoIlB0QWRBbm5veU1uQWJzVmFyc1NraXBBbWJDb25QZXJtaW1wLnBkZiIpDQp9DQoNCmBgYA0KDQpgYGB7ciwgZmlnLndpZHRoPTgsZmlnLmhlaWdodD03fQ0KDQojIFBsb3Qgb25seSBwb3NpdGl2ZSB2YWx1ZXMgZGlzcmVnYXJkaW5nIGFtYmllbnQgTEFlcQ0KDQpyZXN1bHRzT3V0QWJzLmNvbmltcFB0diA8LSByZXN1bHRzT3V0QWJzLmNvbmltcCB8Pg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93bmFtZXNfdG9fY29sdW1uKCdNZXRyaWMnKSB8Pg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyX2lmKGlzLm51bWVyaWMsIGFsbF92YXJzKC4gPiAwKSkgfD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHVtbl90b19yb3duYW1lcygnTWV0cmljJykNCg0KcEJhciA8LSBnZ3Bsb3Qoc2xpY2UocmVzdWx0c091dEFicy5jb25pbXBQdHYsIDE6bigpLTEpKSArIGdlb21fY29sKGFlcyh4PWZhY3Rvcihyb3duYW1lcyhzbGljZShyZXN1bHRzT3V0QWJzLmNvbmltcFB0diwgMTpuKCktMSkpLCBsZXZlbHM9cm93bmFtZXMoc2xpY2UocmVzdWx0c091dEFicy5jb25pbXBQdHYsIDE6bigpLTEpKSksIHk9Q29uZFBlcm1JbXApLCBmaWxsPW15Y29sb3Vyc1sxXSwgd2lkdGg9MC41KSArIGxhYnMoeD0iVmFyaWFibGUiLCB5PSJDb25kaXRpb25hbCB2YXJpYWJsZSBwZXJtdXRhdGlvbiBpbXBvcnRhbmNlIChtZWFuIGNoYW5nZSBpbiBhbm5veWFuY2UpIikgKyB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIpLCBwYW5lbC5ncmlkPWVsZW1lbnRfbGluZShjb2xvciA9IHJnYigyMzUsIDIzNSwgMjM1LCAxMDAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCBsaW5ld2lkdGggPSAwLjI1LCBsaW5ldHlwZSA9IDIpKSArIGNvb3JkX2ZsaXAoKQ0KcEJhcg0KDQppZiAoc2F2ZXBsb3RzKXsNCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFkQW5ub3lNbkFic1ZhcnNTa2lwQW1iQ29uUGVybWltcFB0di5zdmciLCB3aWR0aD04LCBoZWlnaHQ9NywgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInN2ZyIpKQ0KICB1bmxpbmsoIlB0QWRBbm5veU1uQWJzVmFyc1NraXBBbWJDb25QZXJtaW1wUHR2LnN2ZyIpDQogIA0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWRBbm5veU1uQWJzVmFyc1NraXBBbWJDb25QZXJtaW1wUHR2LnBkZiIsIHdpZHRoPTgsIGhlaWdodD03LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAicGRmIikpDQogIHVubGluaygiUHRBZEFubm95TW5BYnNWYXJzU2tpcEFtYkNvblBlcm1pbXBQdHYucGRmIikNCn0NCg0KYGBgDQoNClNlbGVjdGVkIG1ldHJpYw0KDQpgYGB7cn0NCg0KYWJzVmFyIDwtICJVQVNMb3VkRUNNQVBvd0F2Z0JpbiINCg0KYGBgDQoNCg0KIyMjIFNRTSBhbmFseXNpcw0KDQojIyMjIFJlcGxhY2UgYW1iaWVudCBvbmx5IHN0aW11bGkNCg0KSGVyZSwgdGhlICdhbWJpZW50IG9ubHknIHN0aW11bGkgYXJlIHJlcGxhY2VkLCBhcyB0aGUgU1FNIGFuYWx5c2lzIGNhbiBpbmNvcnBvcmF0ZSAwIHZhbHVlcyAod2hlcmVhcyBkQiBtZXRyaWNzIGNhbm5vdCBiZSBoYW5kbGVkIGluIHRoaXMgd2F5KS4NCg0KYGBge3J9DQoNCnN0aW1EYXRhQU51bSA8LSByYmluZChzdGltRGF0YUFOdW0sIHN0aW1EYXRhQVtzdGltRGF0YUFbJ1N0aW11bHVzJ10NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA9PSAiQTEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG5hbWVzKHN0aW1EYXRhQU51bSldLA0KICAgICAgICAgICAgICAgICAgICAgIHN0aW1EYXRhQVtzdGltRGF0YUFbJ1N0aW11bHVzJ10NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA9PSAiQTIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG5hbWVzKHN0aW1EYXRhQU51bSldKQ0Kc3RpbURhdGFBTnVtIDwtIGFycmFuZ2Uoc3RpbURhdGFBTnVtLCBTdGltdWx1cykNCg0KYGBgDQoNCiMjIyMgSW5kaXZpZHVhbCBTUU1zDQoNCiMjIyMjIFNoYXJwbmVzcw0KDQojIyMjIyMgU2V0IHZhcmlhYmxlcw0KDQpgYGB7cn0NCg0KaVZhcnMgPC0gYyhhYnNWYXIsICJBbWJpZW50TEFlcSIsICJVQVNTaGFycEF1cklTTzNQb3dBdmdNYXhMUiIsICJVQVNTaGFycEF1cklTTzMwNUV4TWF4TFIiLCAiVUFTU2hhcnBBdXJTSE1Qb3dBdmdNYXhMUiIsICJVQVNTaGFycEF1clNITTA1RXhNYXhMUiIsICJVQVNTaGFycEF1cklTTzFQb3dBdmdNYXhMUiIsICJVQVNTaGFycEF1cklTTzEwNUV4TWF4TFIiLCAiVUFTU2hhcnB2QklTTzFQb3dBdmdNYXhMUiIsICJVQVNTaGFycHZCSVNPMTA1RXhNYXhMUiIsICJVQVNTaGFycERJTlBvd0F2Z01heExSIiwgIlVBU1NoYXJwRElOMDVFeE1heExSIikNCmRWYXIgPC0gImRBbm5veU1lYW4iDQoNCnNlZWRzIDwtIGMoNzA0MSwgOTA1LCA0OTg0NjUxLCA2NTEzMjEzLCAxMjA2NTEpDQoNCmBgYA0KDQojIyMjIyMgSHlwZXJwYXJhbWV0ZXIgdHVuaW5nDQoNCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NH0NCg0KcCA8LSBtdHJ5VHVuZShkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkPXNlZWRzWzFdLA0KICAgICAgICAgICAgIG50cmVlcz1udHJlZXMsIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KcA0KDQpgYGANCg0KU2VsZWN0ZWQgaHlwZXJwYXJhbWV0ZXJzDQoNCmBgYHtyfQ0KDQpudHJlZSA8LSAyNTENCm10cnkgPC0gYXMuaW50ZWdlcihsZW5ndGgoaVZhcnMpLzEuNSkNCg0KYGBgDQoNCiMjIyMjIyBSdW4gbW9kZWwNCg0KVHJhaW4gcHJlbGltaW5hcnkgbW9kZWwNCg0KYGBge3J9DQoNCm5wZXJtIDwtIDUNCg0KcmVzdWx0c091dFNoYXJwIDwtIGNyZlJlZyhkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkc1sxOjJdLCBudHJlZT1udHJlZSwgbXRyeT1tdHJ5LCBwZXJtSW1wQ29uZFRocmVzPXBlcm1JbXBDb25kVGhyZXMsIG5wZXJtPW5wZXJtLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCg0KIyBwcmludCBtb2RlbCBwcmVkaWN0aW9uIHJlc3VsdHMNCnJlc3VsdHNPdXRTaGFycCRPT0JfUk1TRQ0KcmVzdWx0c091dFNoYXJwJE9PQl9NQUUNCnJlc3VsdHNPdXRTaGFycCRSc3F1YXJlZA0KDQpgYGANCg0KVHJhaW4gbXVsdGlwbGUgc2VlZHMgbW9kZWwNCg0KYGBge3J9DQoNCnJlc3VsdHNPdXRTaGFycCA8LSBtdWx0aV9jcmZSZWcoZGF0YUluPXN0aW1EYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHMsIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dFNoYXJwJE9PQl9STVNFDQpyZXN1bHRzT3V0U2hhcnAkT09CX01BRQ0KcmVzdWx0c091dFNoYXJwJFJzcXVhcmVkDQoNCmBgYA0KDQoNCmBgYHtyfQ0KIyBzdG9yZSByZXN1bHRzDQpyZXNkQW5ub3lNbkZpdFsnQWJzIHNoYXJwJywgJ1JNU0UnXSA8LSByZXN1bHRzT3V0U2hhcnAkT09CX1JNU0UNCnJlc2RBbm5veU1uRml0WydBYnMgc2hhcnAnLCAnTUFFJ10gPC0gcmVzdWx0c091dFNoYXJwJE9PQl9NQUUNCnJlc2RBbm5veU1uRml0WydBYnMgc2hhcnAnLCAnUnNxdWFyZWQnXSA8LSByZXN1bHRzT3V0U2hhcnAkUnNxdWFyZWQNCnJlc2RBbm5veU1uUGVybUltcCRBYnNTaGFycCA8LSByZXN1bHRzT3V0U2hhcnAkY29uZGl0aW9uYWxfcGVybWltcA0KDQpgYGANCg0KIyMjIyMjIFBsb3QgcmVzdWx0cw0KDQpgYGB7ciwgZmlnLndpZHRoPTgsZmlnLmhlaWdodD00Ljl9DQpwYXIobWFpPWMoMCwzLDAsMCkpDQoNCiMgcGxvdCBjb25kaXRpb25hbCBpbXBvcnRhbmNlDQpyZXN1bHRzT3V0U2hhcnAuY29uaW1wIDwtIGFycmFuZ2UocmVzdWx0c091dFNoYXJwJGNvbmRpdGlvbmFsX3Blcm1pbXAsIGRlc2Mocm93X251bWJlcigpKSkNCg0KcEJhciA8LSBnZ3Bsb3QocmVzdWx0c091dFNoYXJwLmNvbmltcCkgKyBnZW9tX2NvbChhZXMoeD1mYWN0b3Iocm93bmFtZXMocmVzdWx0c091dFNoYXJwLmNvbmltcCksIGxldmVscz1yb3duYW1lcyhyZXN1bHRzT3V0U2hhcnAuY29uaW1wKSksIHk9Q29uZFBlcm1JbXApLCBmaWxsPW15Y29sb3Vyc1syXSwgd2lkdGg9MC41KSArIGxhYnMoeD0iVmFyaWFibGUiLCB5PSJDb25kaXRpb25hbCB2YXJpYWJsZSBwZXJtdXRhdGlvbiBpbXBvcnRhbmNlIChtZWFuIGNoYW5nZSBpbiBhbm5veWFuY2UpIikgKyBnZ3RpdGxlKCJTaGFycG5lc3MiKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiksIHBhbmVsLmdyaWQ9ZWxlbWVudF9saW5lKGNvbG9yID0gcmdiKDIzNSwgMjM1LCAyMzUsIDEwMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksIGxpbmV3aWR0aCA9IDAuMjUsIGxpbmV0eXBlID0gMikpICsgY29vcmRfZmxpcCgpDQpwQmFyDQoNCmlmIChzYXZlcGxvdHMpew0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWRBbm5veU1uU2hhcnBDb25QZXJtaW1wLnN2ZyIsIHdpZHRoPTgsIGhlaWdodD00LjksIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJzdmciKSkNCiAgdW5saW5rKCJQdEFkQW5ub3lNblNoYXJwQ29uUGVybWltcC5zdmciKQ0KICANCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFkQW5ub3lNblNoYXJwQ29uUGVybWltcC5wZGYiLCB3aWR0aD04LCBoZWlnaHQ9NC45LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAicGRmIikpDQogIHVubGluaygiUHRBZEFubm95TW5TaGFycENvblBlcm1pbXAucGRmIikNCn0NCg0KDQpgYGANCg0KU2VsZWN0ZWQgbWV0cmljDQoNCmBgYHtyfQ0KDQpzaGFycFZhciA8LSAiVUFTU2hhcnBBdXJJU08zMDVFeE1heExSIg0KDQpgYGANCg0KIyMjIyMgVG9uYWwgbG91ZG5lc3MgYW5kIHRvbmFsaXR5DQoNCiMjIyMjIyBTZXQgdmFyaWFibGVzDQoNCmBgYHtyfQ0KDQppVmFycyA8LSBjKGFic1ZhciwgIkFtYmllbnRMQWVxIiwgIlVBU1RvbmFsRUNNQUF2Z01heExSIiwgIlVBU1RvbmFsU0hNSW50MDVFeE1heExSIiwgIlVBU1RvbmFsU0hNSW50QXZnTWF4TFIiLCAiVUFTVG9uYWxFQ01BMDVFeE1heExSIiwgIlVBU1RvbkxkRUNNQVBvd0F2Z0JpbiIsICJVQVNUb25MZEVDTUEwNUV4QmluIiwgIlVBU1RvbmFsQXVyQXZnTWF4TFIiLCAiVUFTVG9uYWxBdXIwNUV4TWF4TFIiLCAiVUFTVG9uYWxBdXIxMEV4TWF4TFIiKQ0KZFZhciA8LSAiZEFubm95TWVhbiINCg0Kc2VlZHMgPC0gYyg1NDAsIDEwNDc5OCwgNDU2NDY0LCA4NzMzMSwgOTQ1NjQpDQoNCmBgYA0KDQojIyMjIyMgSHlwZXJwYXJhbWV0ZXIgdHVuaW5nDQoNCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NH0NCg0KcCA8LSBtdHJ5VHVuZShkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkPXNlZWRzWzFdLA0KICAgICAgICAgICAgIG50cmVlcz1udHJlZXMsIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KcA0KDQpgYGANCg0KU2VsZWN0ZWQgaHlwZXJwYXJhbWV0ZXJzDQoNCmBgYHtyfQ0KDQpudHJlZSA8LSAxMDAxDQptdHJ5IDwtIGFzLmludGVnZXIobGVuZ3RoKGlWYXJzKS8xLjUpDQoNCmBgYA0KDQojIyMjIyMgUnVuIG1vZGVsDQoNClRyYWluIHByZWxpbWluYXJ5IG1vZGVsDQoNCmBgYHtyfQ0KIyBUb25hbGl0eSB3aXRoIHRvbmFsIGxvdWRuZXNzDQoNCm5wZXJtIDwtIDUNCg0KcmVzdWx0c091dFRvbmFsMSA8LSBjcmZSZWcoZGF0YUluPXN0aW1EYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHNbMToyXSwgbnRyZWU9bnRyZWUsIG10cnk9bXRyeSwgcGVybUltcENvbmRUaHJlcz1wZXJtSW1wQ29uZFRocmVzLCBucGVybT1ucGVybSwgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQoNCiMgcHJpbnQgbW9kZWwgcHJlZGljdGlvbiByZXN1bHRzDQpyZXN1bHRzT3V0VG9uYWwxJE9PQl9STVNFDQpyZXN1bHRzT3V0VG9uYWwxJE9PQl9NQUUNCnJlc3VsdHNPdXRUb25hbDEkUnNxdWFyZWQNCmBgYA0KDQpUcmFpbiBtdWx0aXBsZSBzZWVkcyBtb2RlbA0KDQpgYGB7cn0NCiMgVG9uYWxpdHkgd2l0aCB0b25hbCBsb3VkbmVzcw0KDQpyZXN1bHRzT3V0VG9uYWwxIDwtIG11bHRpX2NyZlJlZyhkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkcywgbnRyZWU9bnRyZWUsIG10cnk9bXRyeSwgcGVybUltcENvbmRUaHJlcz1wZXJtSW1wQ29uZFRocmVzLCBucGVybT1ucGVybSwgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQoNCiMgcHJpbnQgbW9kZWwgcHJlZGljdGlvbiByZXN1bHRzDQpyZXN1bHRzT3V0VG9uYWwxJE9PQl9STVNFDQpyZXN1bHRzT3V0VG9uYWwxJE9PQl9NQUUNCnJlc3VsdHNPdXRUb25hbDEkUnNxdWFyZWQNCg0KYGBgDQoNCmBgYHtyfQ0KIyBzdG9yZSByZXN1bHRzDQpyZXNkQW5ub3lNbkZpdFsnQWJzIHRvbmFsIGluYyBsb3VkJywgJ1JNU0UnXSA8LSByZXN1bHRzT3V0VG9uYWwxJE9PQl9STVNFDQpyZXNkQW5ub3lNbkZpdFsnQWJzIHRvbmFsIGluYyBsb3VkJywgJ01BRSddIDwtIHJlc3VsdHNPdXRUb25hbDEkT09CX01BRQ0KcmVzZEFubm95TW5GaXRbJ0FicyB0b25hbCBpbmMgbG91ZCcsICdSc3F1YXJlZCddIDwtIHJlc3VsdHNPdXRUb25hbDEkUnNxdWFyZWQNCnJlc2RBbm5veU1uUGVybUltcCRBYnNUb25hbDEgPC0gcmVzdWx0c091dFRvbmFsMSRjb25kaXRpb25hbF9wZXJtaW1wDQoNCmBgYA0KDQojIyMjIyMgUGxvdCByZXN1bHRzDQoNCmBgYHtyLCBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTMuOH0NCg0KcGFyKG1haT1jKDAsMywwLDApKQ0KDQojIHBsb3QgY29uZGl0aW9uYWwgaW1wb3J0YW5jZQ0KcmVzdWx0c091dFRvbmFsMS5jb25pbXAgPC0gYXJyYW5nZShyZXN1bHRzT3V0VG9uYWwxJGNvbmRpdGlvbmFsX3Blcm1pbXAsIGRlc2Mocm93X251bWJlcigpKSkNCg0KcEJhciA8LSBnZ3Bsb3QocmVzdWx0c091dFRvbmFsMS5jb25pbXApICsgZ2VvbV9jb2woYWVzKHg9ZmFjdG9yKHJvd25hbWVzKHJlc3VsdHNPdXRUb25hbDEuY29uaW1wKSwgbGV2ZWxzPXJvd25hbWVzKHJlc3VsdHNPdXRUb25hbDEuY29uaW1wKSksIHk9Q29uZFBlcm1JbXApLCBmaWxsPW15Y29sb3Vyc1szXSwgd2lkdGg9MC41KSArIGxhYnMoeD0iVmFyaWFibGUiLCB5PSJDb25kaXRpb25hbCB2YXJpYWJsZSBwZXJtdXRhdGlvbiBpbXBvcnRhbmNlIChtZWFuIGNoYW5nZSBpbiBhbm5veWFuY2UpIikgKyBnZ3RpdGxlKCJUb25hbGl0eSBpbmMuIHRvbmFsIGxvdWRuZXNzIikgKyB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIpLCBwYW5lbC5ncmlkPWVsZW1lbnRfbGluZShjb2xvciA9IHJnYigyMzUsIDIzNSwgMjM1LCAxMDAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCBsaW5ld2lkdGggPSAwLjI1LCBsaW5ldHlwZSA9IDIpKSArIGNvb3JkX2ZsaXAoeWxpbT1jKDAsIDEuMikpDQpwQmFyDQoNCmlmIChzYXZlcGxvdHMpew0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWRBbm5veU1uVG9uYWxMZENvblBlcm1pbXAuc3ZnIiwgd2lkdGg9OCwgaGVpZ2h0PTMuOCwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInN2ZyIpKQ0KICB1bmxpbmsoIlB0QWRBbm5veU1uVG9uYWxMZENvblBlcm1pbXAuc3ZnIikNCiAgDQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBZEFubm95TW5Ub25hbExkQ29uUGVybWltcC5wZGYiLCB3aWR0aD04LCBoZWlnaHQ9My44LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAicGRmIikpDQogIHVubGluaygiUHRBZEFubm95TW5Ub25hbExkQ29uUGVybWltcC5wZGYiKQ0KfQ0KDQpgYGANCg0KU2VsZWN0ZWQgbWV0cmljDQoNCmBgYHtyfQ0KDQp0b25MZFZhciA8LSAiVUFTVG9uTGRFQ01BUG93QXZnQmluIg0KDQpgYGANCg0KIyMjIyMgVG9uYWxpdHkgd2l0aG91dCB0b25hbCBsb3VkbmVzcw0KDQojIyMjIyMgU2V0IHZhcmlhYmxlcw0KDQpgYGB7cn0NCg0KaVZhcnMgPC0gYyhhYnNWYXIsICJBbWJpZW50TEFlcSIsICJVQVNUb25hbEVDTUFBdmdNYXhMUiIsICJVQVNUb25hbFNITUludDA1RXhNYXhMUiIsICJVQVNUb25hbFNITUludEF2Z01heExSIiwgIlVBU1RvbmFsRUNNQTA1RXhNYXhMUiIsICJVQVNUb25hbEF1ckF2Z01heExSIiwgIlVBU1RvbmFsQXVyMDVFeE1heExSIiwgIlVBU1RvbmFsQXVyMTBFeE1heExSIikNCmRWYXIgPC0gImRBbm5veU1lYW4iDQoNCnNlZWRzIDwtIGMoMTU2MDg5LCA1ODYwLCAxMDUyOCwgODk1NDEsIDQ2ODUxNDYpDQoNCmBgYA0KDQojIyMjIyMgSHlwZXJwYXJhbWV0ZXIgdHVuaW5nDQoNCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NH0NCg0KcCA8LSBtdHJ5VHVuZShkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkPXNlZWRzWzFdLA0KICAgICAgICAgICAgIG50cmVlcz1udHJlZXMsIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KcA0KDQpgYGANCg0KU2VsZWN0ZWQgaHlwZXJwYXJhbWV0ZXJzDQoNCmBgYHtyfQ0KDQpudHJlZSA8LSAxMDAxDQptdHJ5IDwtIGFzLmludGVnZXIobGVuZ3RoKGlWYXJzKS8xLjUpDQoNCmBgYA0KDQojIyMjIyMgUnVuIG1vZGVsDQoNClRyYWluIHByZWxpbWluYXJ5IG1vZGVsDQoNCmBgYHtyfQ0KIyBUb25hbGl0eQ0KDQpucGVybSA8LSA1DQoNCnJlc3VsdHNPdXRUb25hbDIgPC0gY3JmUmVnKGRhdGFJbj1zdGltRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzWzE6Ml0sIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dFRvbmFsMiRPT0JfUk1TRQ0KcmVzdWx0c091dFRvbmFsMiRPT0JfTUFFDQpyZXN1bHRzT3V0VG9uYWwyJFJzcXVhcmVkDQoNCmBgYA0KDQpUcmFpbiBtdWx0aXBsZSBzZWVkcyBtb2RlbA0KDQpgYGB7cn0NCiMgVG9uYWxpdHkNCg0KcmVzdWx0c091dFRvbmFsMiA8LSBtdWx0aV9jcmZSZWcoZGF0YUluPXN0aW1EYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHMsIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dFRvbmFsMiRPT0JfUk1TRQ0KcmVzdWx0c091dFRvbmFsMiRPT0JfTUFFDQpyZXN1bHRzT3V0VG9uYWwyJFJzcXVhcmVkDQoNCmBgYA0KDQoNCmBgYHtyfQ0KDQojIHN0b3JlIHJlc3VsdHMNCnJlc2RBbm5veU1uRml0WydBYnMgdG9uYWwgbm8gbG91ZCcsICdSTVNFJ10gPC0gcmVzdWx0c091dFRvbmFsMiRPT0JfUk1TRQ0KcmVzZEFubm95TW5GaXRbJ0FicyB0b25hbCBubyBsb3VkJywgJ01BRSddIDwtIHJlc3VsdHNPdXRUb25hbDIkT09CX01BRQ0KcmVzZEFubm95TW5GaXRbJ0FicyB0b25hbCBubyBsb3VkJywgJ1JzcXVhcmVkJ10gPC0gcmVzdWx0c091dFRvbmFsMiRSc3F1YXJlZA0KcmVzZEFubm95TW5QZXJtSW1wJEFic1RvbmFsMiA8LSByZXN1bHRzT3V0VG9uYWwyJGNvbmRpdGlvbmFsX3Blcm1pbXANCg0KYGBgDQoNCiMjIyMjIyBQbG90IHJlc3VsdHMNCg0KYGBge3IsIGZpZy53aWR0aD04LGZpZy5oZWlnaHQ9My4yfQ0KcGFyKG1haT1jKDAsMywwLDApKQ0KDQojIHBsb3QgY29uZGl0aW9uYWwgaW1wb3J0YW5jZQ0KcmVzdWx0c091dFRvbmFsMi5jb25pbXAgPC0gYXJyYW5nZShyZXN1bHRzT3V0VG9uYWwyJGNvbmRpdGlvbmFsX3Blcm1pbXAsIGRlc2Mocm93X251bWJlcigpKSkNCg0KcEJhciA8LSBnZ3Bsb3QocmVzdWx0c091dFRvbmFsMi5jb25pbXApICsgZ2VvbV9jb2woYWVzKHg9ZmFjdG9yKHJvd25hbWVzKHJlc3VsdHNPdXRUb25hbDIuY29uaW1wKSwgbGV2ZWxzPXJvd25hbWVzKHJlc3VsdHNPdXRUb25hbDIuY29uaW1wKSksIHk9Q29uZFBlcm1JbXApLCBmaWxsPW15Y29sb3Vyc1szXSwgd2lkdGg9MC41KSArIGxhYnMoeD0iVmFyaWFibGUiLCB5PSJDb25kaXRpb25hbCB2YXJpYWJsZSBwZXJtdXRhdGlvbiBpbXBvcnRhbmNlIChtZWFuIGNoYW5nZSBpbiBhbm5veWFuY2UpIikgKyBnZ3RpdGxlKCJUb25hbGl0eSB3L28gdG9uYWwgbG91ZG5lc3MiKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiksIHBhbmVsLmdyaWQ9ZWxlbWVudF9saW5lKGNvbG9yID0gcmdiKDIzNSwgMjM1LCAyMzUsIDEwMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksIGxpbmV3aWR0aCA9IDAuMjUsIGxpbmV0eXBlID0gMikpICsgY29vcmRfZmxpcCh5bGltPWMoMCwgMS4yKSkNCnBCYXINCg0KaWYgKHNhdmVwbG90cyl7DQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBZEFubm95TW5Ub25hbENvblBlcm1pbXAuc3ZnIiwgd2lkdGg9OCwgaGVpZ2h0PTMuMiwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInN2ZyIpKQ0KICB1bmxpbmsoIlB0QWRBbm5veU1uVG9uYWxDb25QZXJtaW1wLnN2ZyIpDQogIA0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWRBbm5veU1uVG9uYWxDb25QZXJtaW1wLnBkZiIsIHdpZHRoPTgsIGhlaWdodD0zLjIsIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJwZGYiKSkNCiAgdW5saW5rKCJQdEFkQW5ub3lNblRvbmFsQ29uUGVybWltcC5wZGYiKQ0KfQ0KDQoNCmBgYA0KDQpTZWxlY3RlZCBtZXRyaWMNCg0KYGBge3J9DQoNCnRvbmFsVmFyIDwtICJVQVNUb25hbFNITUludDA1RXhNYXhMUiINCg0KYGBgDQoNCiMjIyMjIEZsdWN0dWF0aW9uIHN0cmVuZ3RoDQoNCiMjIyMjIyBTZXQgdmFyaWFibGVzDQoNCmBgYHtyfQ0KDQojIEZsdWN0dWF0aW9uIHN0cmVuZ3RoDQppVmFycyA8LSBjKGFic1ZhciwgIkFtYmllbnRMQWVxIiwgIlVBU0ZsdWN0U0hNMTBFeEJpbiIsICJVQVNGbHVjdFNITTA1RXhCaW4iLCAiVUFTRmx1Y3RGWjEwRXhNYXhMUiIsICJVQVNGbHVjdEZaMDVFeE1heExSIiwgIlVBU0ZsdWN0T1YxMEV4TWF4TFIiLCAiVUFTRmx1Y3RPVjA1RXhNYXhMUiIpDQpkVmFyIDwtICJkQW5ub3lNZWFuIg0KDQpzZWVkcyA8LSBjKDI1MTA3LCA1NDYwOTgsIDE5NSwgNTkzNywgMTAyNjU4KQ0KDQpgYGANCg0KDQojIyMjIyMgSHlwZXJwYXJhbWV0ZXIgdHVuaW5nDQoNCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NH0NCg0KcCA8LSBtdHJ5VHVuZShkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkPXNlZWRzWzFdLA0KICAgICAgICAgICAgIG50cmVlcz1udHJlZXMsIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KcA0KDQpgYGANCg0KU2VsZWN0ZWQgaHlwZXJwYXJhbWV0ZXJzDQoNCmBgYHtyfQ0KDQpudHJlZSA8LSA1NTAxDQptdHJ5IDwtIGFzLmludGVnZXIobGVuZ3RoKGlWYXJzKS8xLjI1KQ0KDQpgYGANCg0KIyMjIyMjIFJ1biBtb2RlbA0KDQpUcmFpbiBwcmVsaW1pbmFyeSBtb2RlbA0KDQpgYGB7cn0NCg0KbnBlcm0gPC0gNQ0KDQpyZXN1bHRzT3V0Rmx1Y3QgPC0gY3JmUmVnKGRhdGFJbj1zdGltRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzWzE6Ml0sIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dEZsdWN0JE9PQl9STVNFDQpyZXN1bHRzT3V0Rmx1Y3QkT09CX01BRQ0KcmVzdWx0c091dEZsdWN0JFJzcXVhcmVkDQoNCmBgYA0KDQpUcmFpbiBtdWx0aXBsZSBzZWVkcyBtb2RlbA0KDQpgYGB7cn0NCg0KcmVzdWx0c091dEZsdWN0IDwtIG11bHRpX2NyZlJlZyhkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkcywgbnRyZWU9bnRyZWUsIG10cnk9bXRyeSwgcGVybUltcENvbmRUaHJlcz1wZXJtSW1wQ29uZFRocmVzLCBucGVybT1ucGVybSwgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQoNCiMgcHJpbnQgbW9kZWwgcHJlZGljdGlvbiByZXN1bHRzDQpyZXN1bHRzT3V0Rmx1Y3QkT09CX1JNU0UNCnJlc3VsdHNPdXRGbHVjdCRPT0JfTUFFDQpyZXN1bHRzT3V0Rmx1Y3QkUnNxdWFyZWQNCg0KYGBgDQoNCg0KYGBge3J9DQoNCiMgc3RvcmUgcmVzdWx0cw0KcmVzZEFubm95TW5GaXRbJ0FicyBmbHVjdCcsICdSTVNFJ10gPC0gcmVzdWx0c091dEZsdWN0JE9PQl9STVNFDQpyZXNkQW5ub3lNbkZpdFsnQWJzIGZsdWN0JywgJ01BRSddIDwtIHJlc3VsdHNPdXRGbHVjdCRPT0JfTUFFDQpyZXNkQW5ub3lNbkZpdFsnQWJzIGZsdWN0JywgJ1JzcXVhcmVkJ10gPC0gcmVzdWx0c091dEZsdWN0JFJzcXVhcmVkDQpyZXNkQW5ub3lNblBlcm1JbXAkQWJzRmx1Y3QgPC0gcmVzdWx0c091dEZsdWN0JGNvbmRpdGlvbmFsX3Blcm1pbXANCg0KYGBgDQoNCiMjIyMjIyBQbG90IHJlc3VsdHMNCg0KYGBge3IsIGZpZy53aWR0aD04LGZpZy5oZWlnaHQ9Mi45fQ0KcGFyKG1haT1jKDAsMywwLDApKQ0KDQojIHBsb3QgY29uZGl0aW9uYWwgaW1wb3J0YW5jZQ0KcmVzdWx0c091dEZsdWN0LmNvbmltcCA8LSBhcnJhbmdlKHJlc3VsdHNPdXRGbHVjdCRjb25kaXRpb25hbF9wZXJtaW1wLCBkZXNjKHJvd19udW1iZXIoKSkpDQoNCnBCYXIgPC0gZ2dwbG90KHJlc3VsdHNPdXRGbHVjdC5jb25pbXApICsgZ2VvbV9jb2woYWVzKHg9ZmFjdG9yKHJvd25hbWVzKHJlc3VsdHNPdXRGbHVjdC5jb25pbXApLCBsZXZlbHM9cm93bmFtZXMocmVzdWx0c091dEZsdWN0LmNvbmltcCkpLCB5PUNvbmRQZXJtSW1wKSwgZmlsbD1teWNvbG91cnNbNF0sIHdpZHRoPTAuNSkgKyBsYWJzKHg9IlZhcmlhYmxlIiwgeT0iQ29uZGl0aW9uYWwgdmFyaWFibGUgcGVybXV0YXRpb24gaW1wb3J0YW5jZSAobWVhbiBjaGFuZ2UgaW4gYW5ub3lhbmNlKSIpICsgZ2d0aXRsZSgiRmx1Y3R1YXRpb24gc3RyZW5ndGgiKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiksIHBhbmVsLmdyaWQ9ZWxlbWVudF9saW5lKGNvbG9yID0gcmdiKDIzNSwgMjM1LCAyMzUsIDEwMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksIGxpbmV3aWR0aCA9IDAuMjUsIGxpbmV0eXBlID0gMikpICsgY29vcmRfZmxpcCgpDQpwQmFyDQoNCmlmIChzYXZlcGxvdHMpew0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWRBbm5veU1uRmx1Y3RDb25QZXJtaW1wLnN2ZyIsIHdpZHRoPTgsIGhlaWdodD0yLjksIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJzdmciKSkNCiAgdW5saW5rKCJQdEFkQW5ub3lNbkZsdWN0Q29uUGVybWltcC5zdmciKQ0KICANCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFkQW5ub3lNbkZsdWN0Q29uUGVybWltcC5wZGYiLCB3aWR0aD04LCBoZWlnaHQ9Mi45LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAicGRmIikpDQogIHVubGluaygiUHRBZEFubm95TW5GbHVjdENvblBlcm1pbXAucGRmIikNCn0NCg0KYGBgDQoNClNlbGVjdGVkIG1ldHJpYw0KDQpgYGB7cn0NCg0KZmx1Y3RWYXIgPC0gIlVBU0ZsdWN0T1YxMEV4TWF4TFIiDQoNCmBgYA0KDQojIyMjIyBSb3VnaG5lc3MNCg0KIyMjIyMjIFNldCB2YXJpYWJsZXMNCg0KYGBge3J9DQoNCiMgUm91Z2huZXNzDQppVmFycyA8LSBjKGFic1ZhciwgIkFtYmllbnRMQWVxIiwgIlVBU1JvdWdoRUNNQTEwRXhCaW4iLCAiVUFTUm91Z2hFQ01BMDVFeEJpbiIsICJVQVNSb3VnaEZaMTBFeE1heExSIiwgIlVBU1JvdWdoRlowNUV4TWF4TFIiLCAiVUFTUm91Z2hEVzEwRXhNYXhMUiIsICJVQVNSb3VnaERXMDVFeE1heExSIikNCmRWYXIgPC0gImRBbm5veU1lYW4iDQoNCnNlZWRzIDwtIGMoNDcwMSwgNTIxODcsIDE2NTg5LCA2NTIxNywgMTY4OTMpDQoNCmBgYA0KDQojIyMjIyMgSHlwZXJwYXJhbWV0ZXIgdHVuaW5nDQoNCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NH0NCg0KcCA8LSBtdHJ5VHVuZShkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkPXNlZWRzWzFdLA0KICAgICAgICAgICAgIG50cmVlcz1udHJlZXMsIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KcA0KDQpgYGANCg0KU2VsZWN0ZWQgaHlwZXJwYXJhbWV0ZXJzDQoNCmBgYHtyfQ0KDQpudHJlZSA8LSAyNTAxDQptdHJ5IDwtIGFzLmludGVnZXIobGVuZ3RoKGlWYXJzKS8xLjI1KQ0KDQpgYGANCg0KIyMjIyMjIFJ1biBtb2RlbA0KDQpUcmFpbiBwcmVsaW1pbmFyeSBtb2RlbA0KDQpgYGB7cn0NCg0KbnBlcm0gPC0gNQ0KDQpyZXN1bHRzT3V0Um91Z2ggPC0gY3JmUmVnKGRhdGFJbj1zdGltRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzWzE6Ml0sIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dFJvdWdoJE9PQl9STVNFDQpyZXN1bHRzT3V0Um91Z2gkT09CX01BRQ0KcmVzdWx0c091dFJvdWdoJFJzcXVhcmVkDQoNCmBgYA0KDQpUcmFpbiBtdWx0aXBsZSBzZWVkcyBtb2RlbA0KDQpgYGB7cn0NCg0KcmVzdWx0c091dFJvdWdoIDwtIG11bHRpX2NyZlJlZyhkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkcywgbnRyZWU9bnRyZWUsIG10cnk9bXRyeSwgcGVybUltcENvbmRUaHJlcz1wZXJtSW1wQ29uZFRocmVzLCBucGVybT1ucGVybSwgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQoNCiMgcHJpbnQgbW9kZWwgcHJlZGljdGlvbiByZXN1bHRzDQpyZXN1bHRzT3V0Um91Z2gkT09CX1JNU0UNCnJlc3VsdHNPdXRSb3VnaCRPT0JfTUFFDQpyZXN1bHRzT3V0Um91Z2gkUnNxdWFyZWQNCg0KYGBgDQoNCmBgYHtyfQ0KIyBzdG9yZSByZXN1bHRzDQpyZXNkQW5ub3lNbkZpdFsnQWJzIHJvdWdoJywgJ1JNU0UnXSA8LSByZXN1bHRzT3V0Um91Z2gkT09CX1JNU0UNCnJlc2RBbm5veU1uRml0WydBYnMgcm91Z2gnLCAnTUFFJ10gPC0gcmVzdWx0c091dFJvdWdoJE9PQl9NQUUNCnJlc2RBbm5veU1uRml0WydBYnMgcm91Z2gnLCAnUnNxdWFyZWQnXSA8LSByZXN1bHRzT3V0Um91Z2gkUnNxdWFyZWQNCnJlc2RBbm5veU1uUGVybUltcCRBYnNSb3VnaCA8LSByZXN1bHRzT3V0Um91Z2gkY29uZGl0aW9uYWxfcGVybWltcA0KDQpgYGANCg0KIyMjIyMjIFBsb3QgcmVzdWx0cw0KDQpgYGB7ciwgZmlnLndpZHRoPTgsZmlnLmhlaWdodD0yLjl9DQpwYXIobWFpPWMoMCwzLDAsMCkpDQoNCiMgcGxvdCBjb25kaXRpb25hbCBpbXBvcnRhbmNlDQpyZXN1bHRzT3V0Um91Z2guY29uaW1wIDwtIGFycmFuZ2UocmVzdWx0c091dFJvdWdoJGNvbmRpdGlvbmFsX3Blcm1pbXAsIGRlc2Mocm93X251bWJlcigpKSkNCg0KcEJhciA8LSBnZ3Bsb3QocmVzdWx0c091dFJvdWdoLmNvbmltcCkgKyBnZW9tX2NvbChhZXMoeD1mYWN0b3Iocm93bmFtZXMocmVzdWx0c091dFJvdWdoLmNvbmltcCksIGxldmVscz1yb3duYW1lcyhyZXN1bHRzT3V0Um91Z2guY29uaW1wKSksIHk9Q29uZFBlcm1JbXApLCBmaWxsPW15Y29sb3Vyc1s1XSwgd2lkdGg9MC41KSArIGxhYnMoeD0iVmFyaWFibGUiLCB5PSJDb25kaXRpb25hbCB2YXJpYWJsZSBwZXJtdXRhdGlvbiBpbXBvcnRhbmNlIChtZWFuIGNoYW5nZSBpbiBhbm5veWFuY2UpIikgKyBnZ3RpdGxlKCJSb3VnaG5lc3MiKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiksIHBhbmVsLmdyaWQ9ZWxlbWVudF9saW5lKGNvbG9yID0gcmdiKDIzNSwgMjM1LCAyMzUsIDEwMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksIGxpbmV3aWR0aCA9IDAuMjUsIGxpbmV0eXBlID0gMikpICsgY29vcmRfZmxpcCgpDQpwQmFyDQoNCmlmIChzYXZlcGxvdHMpew0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWRBbm5veU1uUm91Z2hDb25QZXJtaW1wLnN2ZyIsIHdpZHRoPTgsIGhlaWdodD0yLjksIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJzdmciKSkNCiAgdW5saW5rKCJQdEFkQW5ub3lNblJvdWdoQ29uUGVybWltcC5zdmciKQ0KICANCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFkQW5ub3lNblJvdWdoQ29uUGVybWltcC5wZGYiLCB3aWR0aD04LCBoZWlnaHQ9Mi45LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAicGRmIikpDQogIHVubGluaygiUHRBZEFubm95TW5Sb3VnaENvblBlcm1pbXAucGRmIikNCn0NCg0KDQpgYGANCg0KU2VsZWN0ZWQgbWV0cmljDQoNCmBgYHtyfQ0KDQpyb3VnaFZhciA8LSAiVUFTUm91Z2hGWjA1RXhNYXhMUiINCg0KYGBgDQoNCiMjIyMjIEltcHVsc2l2ZW5lc3MNCg0KIyMjIyMjIFNldCB2YXJpYWJsZXMNCg0KYGBge3J9DQojIEltcHVsc2l2ZW5lc3MNCmlWYXJzIDwtIGMoYWJzVmFyLCAiQW1iaWVudExBZXEiLCAiVUFTSW1wdWxzU0hNQXZnTWF4TFIiLCAiVUFTSW1wdWxzU0hNMDVFeE1heExSIiwgIlVBU0ltcHVsc1NITVBvd0F2Z01heExSIikNCmRWYXIgPC0gImRBbm5veU1lYW4iDQoNCnNlZWRzIDwtIGMoODQ5NSwgNTk4NjcsIDU0MTYsIDk4NDMsIDg2KQ0KDQpgYGANCg0KIyMjIyMjIEh5cGVycGFyYW1ldGVyIHR1bmluZw0KDQpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTR9DQoNCnAgPC0gbXRyeVR1bmUoZGF0YUluPXN0aW1EYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZD1zZWVkc1sxXSwNCiAgICAgICAgICAgICBudHJlZXM9bnRyZWVzLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCnANCg0KYGBgDQoNClNlbGVjdGVkIGh5cGVycGFyYW1ldGVycw0KDQpgYGB7cn0NCg0KbnRyZWUgPC0gMjUxDQptdHJ5IDwtIGFzLmludGVnZXIobGVuZ3RoKGlWYXJzKS8xLjI1KQ0KDQpgYGANCg0KDQojIyMjIyMgUnVuIG1vZGVsDQoNClRyYWluIHByZWxpbWluYXJ5IG1vZGVsDQoNCmBgYHtyfQ0KDQpucGVybSA8LSA1DQoNCnJlc3VsdHNPdXRJbXB1bHMgPC0gY3JmUmVnKGRhdGFJbj1zdGltRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzWzE6Ml0sIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dEltcHVscyRPT0JfUk1TRQ0KcmVzdWx0c091dEltcHVscyRPT0JfTUFFDQpyZXN1bHRzT3V0SW1wdWxzJFJzcXVhcmVkDQoNCmBgYA0KDQpUcmFpbiBtdWx0aXBsZSBzZWVkcyBtb2RlbA0KDQpgYGB7cn0NCg0KcmVzdWx0c091dEltcHVscyA8LSBtdWx0aV9jcmZSZWcoZGF0YUluPXN0aW1EYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHMsIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dEltcHVscyRPT0JfUk1TRQ0KcmVzdWx0c091dEltcHVscyRPT0JfTUFFDQpyZXN1bHRzT3V0SW1wdWxzJFJzcXVhcmVkDQoNCmBgYA0KDQpgYGB7cn0NCg0KIyBzdG9yZSByZXN1bHRzDQpyZXNkQW5ub3lNbkZpdFsnQWJzIGltcHVscycsICdSTVNFJ10gPC0gcmVzdWx0c091dEltcHVscyRPT0JfUk1TRQ0KcmVzZEFubm95TW5GaXRbJ0FicyBpbXB1bHMnLCAnTUFFJ10gPC0gcmVzdWx0c091dEltcHVscyRPT0JfTUFFDQpyZXNkQW5ub3lNbkZpdFsnQWJzIGltcHVscycsICdSc3F1YXJlZCddIDwtIHJlc3VsdHNPdXRJbXB1bHMkUnNxdWFyZWQNCnJlc2RBbm5veU1uUGVybUltcCRBYnNJbXB1bHMgPC0gcmVzdWx0c091dEltcHVscyRjb25kaXRpb25hbF9wZXJtaW1wDQoNCmBgYA0KDQojIyMjIyMgUGxvdCByZXN1bHRzDQoNCmBgYHtyLCBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTJ9DQpwYXIobWFpPWMoMCwzLDAsMCkpDQoNCiMgcGxvdCBjb25kaXRpb25hbCBpbXBvcnRhbmNlDQpyZXN1bHRzT3V0SW1wdWxzLmNvbmltcCA8LSBhcnJhbmdlKHJlc3VsdHNPdXRJbXB1bHMkY29uZGl0aW9uYWxfcGVybWltcCwgZGVzYyhyb3dfbnVtYmVyKCkpKQ0KDQpwQmFyIDwtIGdncGxvdChyZXN1bHRzT3V0SW1wdWxzLmNvbmltcCkgKyBnZW9tX2NvbChhZXMoeD1mYWN0b3Iocm93bmFtZXMocmVzdWx0c091dEltcHVscy5jb25pbXApLCBsZXZlbHM9cm93bmFtZXMocmVzdWx0c091dEltcHVscy5jb25pbXApKSwgeT1Db25kUGVybUltcCksIGZpbGw9bXljb2xvdXJzWzZdLCB3aWR0aD0wLjUpICsgbGFicyh4PSJWYXJpYWJsZSIsIHk9IkNvbmRpdGlvbmFsIHZhcmlhYmxlIHBlcm11dGF0aW9uIGltcG9ydGFuY2UgKG1lYW4gY2hhbmdlIGluIGFubm95YW5jZSkiKSArIGdndGl0bGUoIkltcHVsc2l2ZW5lc3MiKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiksIHBhbmVsLmdyaWQ9ZWxlbWVudF9saW5lKGNvbG9yID0gcmdiKDIzNSwgMjM1LCAyMzUsIDEwMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksIGxpbmV3aWR0aCA9IDAuMjUsIGxpbmV0eXBlID0gMikpICsgY29vcmRfZmxpcCgpDQpwQmFyDQoNCmlmIChzYXZlcGxvdHMpew0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWRBbm5veU1uSW1wdWxzQ29uUGVybWltcC5zdmciLCB3aWR0aD04LCBoZWlnaHQ9MiwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInN2ZyIpKQ0KICB1bmxpbmsoIlB0QWRBbm5veU1uSW1wdWxzQ29uUGVybWltcC5zdmciKQ0KICANCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFkQW5ub3lNbkltcHVsc0NvblBlcm1pbXAucGRmIiwgd2lkdGg9OCwgaGVpZ2h0PTIsIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJwZGYiKSkNCiAgdW5saW5rKCJQdEFkQW5ub3lNbkltcHVsc0NvblBlcm1pbXAucGRmIikNCn0NCg0KYGBgDQoNClNlbGVjdGVkIG1ldHJpYw0KDQpgYGB7cn0NCg0KaW1wdWxzVmFyIDwtICJVQVNJbXB1bHNTSE1BdmdNYXhMUiINCg0KYGBgDQoNCiMjIyMgU1FNIGFuZCBsb3VkbmVzcyBjb21wYXJpc29uDQoNCk5vdyB0aGUgaGlnaGVzdCBpbXBvcnRhbmNlIFNRTXMgYXJlIHJhbmtlZCBhZ2FpbnN0IGVhY2ggb3RoZXIsIGNvbnRyb2xsaW5nIGZvciBVQVMgbG91ZG5lc3MgYW5kIGFtYmllbnQgTEFlcS4NCg0KIyMjIyMgSW5jbHVkZSB0b25hbCBsb3VkbmVzcw0KDQojIyMjIyMgU2V0IHZhcmlhYmxlcw0KDQpgYGB7cn0NCg0KaVZhcnMgPC0gYyhhYnNWYXIsICJBbWJpZW50TEFlcSIsIHNoYXJwVmFyLCB0b25MZFZhciwgZmx1Y3RWYXIsIHJvdWdoVmFyLCBpbXB1bHNWYXIpDQpkVmFyIDwtICJkQW5ub3lNZWFuIg0KDQpzZWVkcyA8LSBjKDcwNDk4LCA0LCAxNDk4NiwgNDUzLCA4NjQpDQoNCmBgYA0KDQojIyMjIyMgSHlwZXJwYXJhbWV0ZXIgdHVuaW5nDQoNCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NH0NCg0KcCA8LSBtdHJ5VHVuZShkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkPXNlZWRzWzFdLA0KICAgICAgICAgICAgIG50cmVlcz1udHJlZXMsIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KcA0KDQpgYGANCg0KU2VsZWN0ZWQgaHlwZXJwYXJhbWV0ZXJzDQoNCmBgYHtyfQ0KDQpudHJlZSA8LSAxMDAxDQptdHJ5IDwtIGFzLmludGVnZXIobGVuZ3RoKGlWYXJzKS8xLjI1KQ0KDQpgYGANCg0KIyMjIyMjIFJ1biBtb2RlbA0KDQpUcmFpbiBwcmVsaW1pbmFyeSBtb2RlbA0KDQpgYGB7cn0NCg0KbnBlcm0gPC0gNQ0KDQpyZXN1bHRzT3V0U1FNczEgPC0gY3JmUmVnKGRhdGFJbj1zdGltRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzWzE6Ml0sIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dFNRTXMxJE9PQl9STVNFDQpyZXN1bHRzT3V0U1FNczEkT09CX01BRQ0KcmVzdWx0c091dFNRTXMxJFJzcXVhcmVkDQoNCmBgYA0KDQpUcmFpbiBtdWx0aXBsZSBzZWVkcyBtb2RlbA0KDQpgYGB7cn0NCg0KcmVzdWx0c091dFNRTXMxIDwtIG11bHRpX2NyZlJlZyhkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkcywgbnRyZWU9bnRyZWUsIG10cnk9bXRyeSwgcGVybUltcENvbmRUaHJlcz1wZXJtSW1wQ29uZFRocmVzLCBucGVybT1ucGVybSwgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQoNCiMgcHJpbnQgbW9kZWwgcHJlZGljdGlvbiByZXN1bHRzDQpyZXN1bHRzT3V0U1FNczEkT09CX1JNU0UNCnJlc3VsdHNPdXRTUU1zMSRPT0JfTUFFDQpyZXN1bHRzT3V0U1FNczEkUnNxdWFyZWQNCg0KYGBgDQoNCmBgYHtyfQ0KDQojIHN0b3JlIHJlc3VsdHMNCnJlc2RBbm5veU1uRml0WydBYnMgU1FNcyBpbmMgdG9uYWwgbG91ZCcsICdSTVNFJ10gPC0gcmVzdWx0c091dFNRTXMxJE9PQl9STVNFDQpyZXNkQW5ub3lNbkZpdFsnQWJzIFNRTXMgaW5jIHRvbmFsIGxvdWQnLCAnTUFFJ10gPC0gcmVzdWx0c091dFNRTXMxJE9PQl9NQUUNCnJlc2RBbm5veU1uRml0WydBYnMgU1FNcyBpbmMgdG9uYWwgbG91ZCcsICdSc3F1YXJlZCddIDwtIHJlc3VsdHNPdXRTUU1zMSRSc3F1YXJlZA0KcmVzZEFubm95TW5QZXJtSW1wJEFic1NRTXMxIDwtIHJlc3VsdHNPdXRTUU1zMSRjb25kaXRpb25hbF9wZXJtaW1wDQoNCmBgYA0KDQojIyMjIyMgUGxvdCByZXN1bHRzDQoNCmBgYHtyLCBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTIuNH0NCnBhcihtYWk9YygwLDMsMCwwKSkNCg0KIyBwbG90IGNvbmRpdGlvbmFsIGltcG9ydGFuY2UNCnJlc3VsdHNPdXRTUU1zMS5jb25pbXAgPC0gYXJyYW5nZShyZXN1bHRzT3V0U1FNczEkY29uZGl0aW9uYWxfcGVybWltcCwgZGVzYyhyb3dfbnVtYmVyKCkpKQ0KDQpwQmFyIDwtIGdncGxvdChyZXN1bHRzT3V0U1FNczEuY29uaW1wKSArIGdlb21fY29sKGFlcyh4PWZhY3Rvcihyb3duYW1lcyhyZXN1bHRzT3V0U1FNczEuY29uaW1wKSwgbGV2ZWxzPXJvd25hbWVzKHJlc3VsdHNPdXRTUU1zMS5jb25pbXApKSwgeT1Db25kUGVybUltcCksIGZpbGw9bXljb2xvdXJzWzddLCB3aWR0aD0wLjUpICsgbGFicyh4PSJWYXJpYWJsZSIsIHk9IkNvbmRpdGlvbmFsIHZhcmlhYmxlIHBlcm11dGF0aW9uIGltcG9ydGFuY2UgKG1lYW4gY2hhbmdlIGluIGFubm95YW5jZSkiKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiksIHBhbmVsLmdyaWQ9ZWxlbWVudF9saW5lKGNvbG9yID0gcmdiKDIzNSwgMjM1LCAyMzUsIDEwMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksIGxpbmV3aWR0aCA9IDAuMjUsIGxpbmV0eXBlID0gMikpICsgY29vcmRfZmxpcCh5bGltPWMoMCwgMSkpDQpwQmFyDQoNCmlmIChzYXZlcGxvdHMpew0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWRBbm5veU1uQWJzU1FNc1RvbkxkQ29uUGVybWltcC5zdmciLCB3aWR0aD04LCBoZWlnaHQ9Mi40LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAic3ZnIikpDQogIHVubGluaygiUHRBZEFubm95TW5BYnNTUU1zVG9uTGRDb25QZXJtaW1wLnN2ZyIpDQogIA0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWRBbm5veU1uQWJzU1FNc1RvbkxkQ29uUGVybWltcC5wZGYiLCB3aWR0aD04LCBoZWlnaHQ9Mi40LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAicGRmIikpDQogIHVubGluaygiUHRBZEFubm95TW5BYnNTUU1zVG9uTGRDb25QZXJtaW1wLnBkZiIpDQp9DQoNCmBgYA0KDQojIyMjIyBFeGNsdWRlIHRvbmFsIGxvdWRuZXNzDQoNCiMjIyMjIyBTZXQgdmFyaWFibGVzDQoNCmBgYHtyfQ0KDQppVmFycyA8LSBjKGFic1ZhciwgIkFtYmllbnRMQWVxIiwgc2hhcnBWYXIsIHRvbmFsVmFyLCBmbHVjdFZhciwgcm91Z2hWYXIsIGltcHVsc1ZhcikNCmRWYXIgPC0gImRBbm5veU1lYW4iDQoNCnNlZWRzIDwtIGMoNTQ2LCA1NzIwMywgMjcwODM1LCA2MDU5MiwgODA5NCkNCg0KYGBgDQoNCiMjIyMjIyBIeXBlcnBhcmFtZXRlciB0dW5pbmcNCg0KYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD00fQ0KDQpwIDwtIG10cnlUdW5lKGRhdGFJbj1zdGltRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWQ9c2VlZHNbMV0sDQogICAgICAgICAgICAgbnRyZWVzPW50cmVlcywgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQpwDQoNCmBgYA0KDQpTZWxlY3RlZCBoeXBlcnBhcmFtZXRlcnMNCg0KYGBge3J9DQoNCm50cmVlIDwtIDQwMDENCm10cnkgPC0gYXMuaW50ZWdlcihsZW5ndGgoaVZhcnMpLzEuMjUpDQoNCmBgYA0KDQojIyMjIyMgUnVuIG1vZGVsDQoNClRyYWluIHByZWxpbWluYXJ5IG1vZGVsDQoNCmBgYHtyfQ0KDQpucGVybSA8LSA1DQoNCnJlc3VsdHNPdXRTUU1zMiA8LSBjcmZSZWcoZGF0YUluPXN0aW1EYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHNbMToyXSwgbnRyZWU9bnRyZWUsIG10cnk9bXRyeSwgcGVybUltcENvbmRUaHJlcz1wZXJtSW1wQ29uZFRocmVzLCBucGVybT1ucGVybSwgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQoNCiMgcHJpbnQgbW9kZWwgcHJlZGljdGlvbiByZXN1bHRzDQpyZXN1bHRzT3V0U1FNczIkT09CX1JNU0UNCnJlc3VsdHNPdXRTUU1zMiRPT0JfTUFFDQpyZXN1bHRzT3V0U1FNczIkUnNxdWFyZWQNCg0KYGBgDQoNClRyYWluIG11bHRpcGxlIHNlZWRzIG1vZGVsDQoNCmBgYHtyfQ0KDQpyZXN1bHRzT3V0U1FNczIgPC0gbXVsdGlfY3JmUmVnKGRhdGFJbj1zdGltRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzLCBudHJlZT1udHJlZSwgbXRyeT1tdHJ5LCBwZXJtSW1wQ29uZFRocmVzPXBlcm1JbXBDb25kVGhyZXMsIG5wZXJtPW5wZXJtLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCg0KIyBwcmludCBtb2RlbCBwcmVkaWN0aW9uIHJlc3VsdHMNCnJlc3VsdHNPdXRTUU1zMiRPT0JfUk1TRQ0KcmVzdWx0c091dFNRTXMyJE9PQl9NQUUNCnJlc3VsdHNPdXRTUU1zMiRSc3F1YXJlZA0KDQpgYGANCg0KYGBge3J9DQoNCiMgc3RvcmUgcmVzdWx0cw0KcmVzZEFubm95TW5GaXRbJ0FicyBTUU1zIG5vIHRvbmFsIGxvdWQnLCAnUk1TRSddIDwtIHJlc3VsdHNPdXRTUU1zMiRPT0JfUk1TRQ0KcmVzZEFubm95TW5GaXRbJ0FicyBTUU1zIG5vIHRvbmFsIGxvdWQnLCAnUk1TRSddIDwtIHJlc3VsdHNPdXRTUU1zMiRPT0JfTUFFDQpyZXNkQW5ub3lNbkZpdFsnQWJzIFNRTXMgbm8gdG9uYWwgbG91ZCcsICdSc3F1YXJlZCddIDwtIHJlc3VsdHNPdXRTUU1zMiRSc3F1YXJlZA0KcmVzZEFubm95TW5QZXJtSW1wJEFic1NRTXMyIDwtIHJlc3VsdHNPdXRTUU1zMiRjb25kaXRpb25hbF9wZXJtaW1wDQoNCmBgYA0KDQojIyMjIyMgUGxvdCByZXN1bHRzDQoNCmBgYHtyLCBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTIuNH0NCnBhcihtYWk9YygwLDMsMCwwKSkNCg0KIyBwbG90IGNvbmRpdGlvbmFsIGltcG9ydGFuY2UNCnJlc3VsdHNPdXRTUU1zMi5jb25pbXAgPC0gYXJyYW5nZShyZXN1bHRzT3V0U1FNczIkY29uZGl0aW9uYWxfcGVybWltcCwgZGVzYyhyb3dfbnVtYmVyKCkpKQ0KDQpwQmFyIDwtIGdncGxvdChyZXN1bHRzT3V0U1FNczIuY29uaW1wKSArIGdlb21fY29sKGFlcyh4PWZhY3Rvcihyb3duYW1lcyhyZXN1bHRzT3V0U1FNczIuY29uaW1wKSwgbGV2ZWxzPXJvd25hbWVzKHJlc3VsdHNPdXRTUU1zMi5jb25pbXApKSwgeT1Db25kUGVybUltcCksIGZpbGw9bXljb2xvdXJzWzddLCB3aWR0aD0wLjUpICsgbGFicyh4PSJWYXJpYWJsZSIsIHk9IkNvbmRpdGlvbmFsIHZhcmlhYmxlIHBlcm11dGF0aW9uIGltcG9ydGFuY2UgKG1lYW4gY2hhbmdlIGluIGFubm95YW5jZSkiKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiksIHBhbmVsLmdyaWQ9ZWxlbWVudF9saW5lKGNvbG9yID0gcmdiKDIzNSwgMjM1LCAyMzUsIDEwMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksIGxpbmV3aWR0aCA9IDAuMjUsIGxpbmV0eXBlID0gMikpICsgY29vcmRfZmxpcCh5bGltPWMoMCwgMSkpDQpwQmFyDQoNCmlmIChzYXZlcGxvdHMpew0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWRBbm5veU1uQWJzU1FNc05vVG9uTGRDb25QZXJtaW1wLnN2ZyIsIHdpZHRoPTgsIGhlaWdodD0yLjQsIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJzdmciKSkNCiAgdW5saW5rKCJQdEFkQW5ub3lNbkFic1NRTXNOb1RvbkxkQ29uUGVybWltcC5zdmciKQ0KICANCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFkQW5ub3lNbkFic1NRTXNOb1RvbkxkQ29uUGVybWltcC5wZGYiLCB3aWR0aD04LCBoZWlnaHQ9Mi40LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAicGRmIikpDQogIHVubGluaygiUHRBZEFubm95TW5BYnNTUU1zTm9Ub25MZENvblBlcm1pbXAucGRmIikNCn0NCg0KYGBgDQoNCiMjIyBEaWZmZXJlbmNlIHZhcmlhYmxlcw0KDQpOZXh0LCB0aGUgZGlmZmVyZW5jZSBtZXRyaWNzIGFyZSBhbmFseXNlZCwgDQoNCiMjIyMgUmVtb3ZlIGFtYmllbnQgb25seSBzdGltdWxpDQoNCkhlcmUsIHRoZSAnYW1iaWVudCBvbmx5JyBzdGltdWxpIGFyZSByZW1vdmVkLCBhcyB0aGUgYW5hbHlzaXMgY2Fubm90IGhhbmRsZSBtaXNzaW5nIHZhbHVlcyBmb3IgZEIgbWV0cmljcy4NCg0KYGBge3J9DQpzdGltRGF0YUFOdW0gPC0gc3RpbURhdGFBTnVtW2NvbXBsZXRlLmNhc2VzKHN0aW1EYXRhQU51bSksXQ0Kc3RpbURhdGFBTnVtJFVBU0xBZXEgPC0gYXMubnVtZXJpYyhzdGltRGF0YUFOdW0kVUFTTEFlcSkNCnN0aW1EYXRhQU51bSRTTlJsZXZlbCA8LSBhcy5udW1lcmljKHN0aW1EYXRhQU51bSRTTlJsZXZlbCkNCmBgYA0KDQojIyMjIFNldCB2YXJpYWJsZXMNCg0KYGBge3J9DQoNCmlWYXJzIDwtIGMobmFtZXMoc3RpbURhdGFBTnVtKVt3aGljaChjb2xuYW1lcyhzdGltRGF0YUFOdW0pPT0iTEFlcUxBRjkwZGlmZiIpOg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoKGNvbG5hbWVzKHN0aW1EYXRhQU51bSk9PSJkSW1wdWxzU0hNMDVFeE1heExSIildLCAiU05SbGV2ZWwiKQ0KZFZhciA8LSAiZEFubm95TWVhbiINCg0Kc2VlZHMgPC0gYyg1NjgzOTIsIDQ5OCwgNDA4OSwgNzgxMzIsIDc0MTgwOSkNCg0KYGBgDQoNCiMjIyMgSHlwZXJwYXJhbWV0ZXIgdHVuaW5nDQoNCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NH0NCg0KcCA8LSBtdHJ5VHVuZShkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkPXNlZWRzWzFdLA0KICAgICAgICAgICAgIG50cmVlcz1udHJlZXMsIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KcA0KDQpgYGANCg0KU2VsZWN0ZWQgaHlwZXJwYXJhbWV0ZXJzDQoNCmBgYHtyfQ0KDQpudHJlZSA8LSAyNTENCm10cnkgPC0gYXMuaW50ZWdlcihsZW5ndGgoaVZhcnMpLzEuMjUpDQoNCmBgYA0KDQojIyMjIFJ1biBtb2RlbA0KDQpUcmFpbiBwcmVsaW1pbmFyeSBtb2RlbA0KDQpgYGB7cn0NCg0KbnBlcm0gPC0gNQ0KDQpyZXN1bHRzT3V0RGlmZnMgPC0gY3JmUmVnKGRhdGFJbj1zdGltRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzWzE6Ml0sIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dERpZmZzJE9PQl9STVNFDQpyZXN1bHRzT3V0RGlmZnMkT09CX01BRQ0KcmVzdWx0c091dERpZmZzJFJzcXVhcmVkDQoNCmBgYA0KDQpUcmFpbiBtdWx0aXBsZSBzZWVkcyBtb2RlbA0KDQpgYGB7cn0NCg0KcmVzdWx0c091dERpZmZzIDwtIG11bHRpX2NyZlJlZyhkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkcywgbnRyZWU9bnRyZWUsIG10cnk9bXRyeSwgcGVybUltcENvbmRUaHJlcz1wZXJtSW1wQ29uZFRocmVzLCBucGVybT1ucGVybSwgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQoNCiMgcHJpbnQgbW9kZWwgcHJlZGljdGlvbiByZXN1bHRzDQpyZXN1bHRzT3V0RGlmZnMkT09CX1JNU0UNCnJlc3VsdHNPdXREaWZmcyRPT0JfTUFFDQpyZXN1bHRzT3V0RGlmZnMkUnNxdWFyZWQNCg0KYGBgDQoNCmBgYHtyfQ0KDQojIHN0b3JlIHJlc3VsdHMNCnJlc2RBbm5veU1uRml0WydEaWZmIHZhcnMnLCAnUk1TRSddIDwtIHJlc3VsdHNPdXREaWZmcyRPT0JfUk1TRQ0KcmVzZEFubm95TW5GaXRbJ0RpZmYgdmFycycsICdNQUUnXSA8LSByZXN1bHRzT3V0RGlmZnMkT09CX01BRQ0KcmVzZEFubm95TW5GaXRbJ0RpZmYgdmFycycsICdSc3F1YXJlZCddIDwtIHJlc3VsdHNPdXREaWZmcyRSc3F1YXJlZA0KcmVzZEFubm95TW5QZXJtSW1wJERpZmZWYXJzIDwtIHJlc3VsdHNPdXREaWZmcyRjb25kaXRpb25hbF9wZXJtaW1wDQoNCmBgYA0KDQojIyMjIFBsb3QgcmVzdWx0cw0KDQpgYGB7ciwgZmlnLndpZHRoPTgsZmlnLmhlaWdodD0xMH0NCnBhcihtYWk9YygwLDMsMCwwKSkNCg0KIyBwbG90IGNvbmRpdGlvbmFsIGltcG9ydGFuY2UNCnJlc3VsdHNPdXREaWZmcy5jb25pbXAgPC0gYXJyYW5nZShyZXN1bHRzT3V0RGlmZnMkY29uZGl0aW9uYWxfcGVybWltcCwgZGVzYyhyb3dfbnVtYmVyKCkpKQ0KDQpwQmFyIDwtIGdncGxvdChyZXN1bHRzT3V0RGlmZnMuY29uaW1wKSArIGdlb21fY29sKGFlcyh4PWZhY3Rvcihyb3duYW1lcyhyZXN1bHRzT3V0RGlmZnMuY29uaW1wKSwgbGV2ZWxzPXJvd25hbWVzKHJlc3VsdHNPdXREaWZmcy5jb25pbXApKSwgeT1Db25kUGVybUltcCksIGZpbGw9bXljb2xvdXJzWzhdLCB3aWR0aD0wLjUpICsgbGFicyh4PSJWYXJpYWJsZSIsIHk9IkNvbmRpdGlvbmFsIHZhcmlhYmxlIHBlcm11dGF0aW9uIGltcG9ydGFuY2UgKG1lYW4gY2hhbmdlIGluIGFubm95YW5jZSkiKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiksIHBhbmVsLmdyaWQ9ZWxlbWVudF9saW5lKGNvbG9yID0gcmdiKDIzNSwgMjM1LCAyMzUsIDEwMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksIGxpbmV3aWR0aCA9IDAuMjUsIGxpbmV0eXBlID0gMikpICsgY29vcmRfZmxpcCgpDQpwQmFyDQoNCmlmIChzYXZlcGxvdHMpew0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWRBbm5veU1uRGlmZlZhcnNDb25QZXJtaW1wLnN2ZyIsIHdpZHRoPTgsIGhlaWdodD0xMCwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInN2ZyIpKQ0KICB1bmxpbmsoIlB0QWRBbm5veU1uRGlmZlZhcnNDb25QZXJtaW1wLnN2ZyIpDQogIA0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWRBbm5veU1uRGlmZlZhcnNDb25QZXJtaW1wLnBkZiIsIHdpZHRoPTgsIGhlaWdodD0xMCwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInBkZiIpKQ0KICB1bmxpbmsoIlB0QWRBbm5veU1uRGlmZlZhcnNDb25QZXJtaW1wLnBkZiIpDQp9DQoNCmBgYA0KDQpgYGB7ciwgZmlnLndpZHRoPTgsZmlnLmhlaWdodD04fQ0KDQojIFBsb3Qgb25seSBwb3NpdGl2ZSB2YWx1ZXMNCnJlc3VsdHNPdXREaWZmcy5jb25pbXBQdHYgPC0gcmVzdWx0c091dERpZmZzLmNvbmltcCB8Pg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvd25hbWVzX3RvX2NvbHVtbignTWV0cmljJykgfD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyX2lmKGlzLm51bWVyaWMsIGFsbF92YXJzKC4gPiAwKSkgfD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sdW1uX3RvX3Jvd25hbWVzKCdNZXRyaWMnKQ0KDQpwQmFyIDwtIGdncGxvdChyZXN1bHRzT3V0RGlmZnMuY29uaW1wUHR2KSArIGdlb21fY29sKGFlcyh4PWZhY3Rvcihyb3duYW1lcyhyZXN1bHRzT3V0RGlmZnMuY29uaW1wUHR2KSwgbGV2ZWxzPXJvd25hbWVzKHJlc3VsdHNPdXREaWZmcy5jb25pbXBQdHYpKSwgeT1Db25kUGVybUltcCksIGZpbGw9bXljb2xvdXJzWzhdLCB3aWR0aD0wLjUpICsgbGFicyh4PSJWYXJpYWJsZSIsIHk9IkNvbmRpdGlvbmFsIHZhcmlhYmxlIHBlcm11dGF0aW9uIGltcG9ydGFuY2UgKG1lYW4gY2hhbmdlIGluIGFubm95YW5jZSkiKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiksIHBhbmVsLmdyaWQ9ZWxlbWVudF9saW5lKGNvbG9yID0gcmdiKDIzNSwgMjM1LCAyMzUsIDEwMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksIGxpbmV3aWR0aCA9IDAuMjUsIGxpbmV0eXBlID0gMikpICsgY29vcmRfZmxpcCgpDQpwQmFyDQoNCmlmIChzYXZlcGxvdHMpew0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWRBbm5veU1uRGlmZlZhcnNDb25QZXJtaW1wUHR2LnN2ZyIsIHdpZHRoPTgsIGhlaWdodD04LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAic3ZnIikpDQogIHVubGluaygiUHRBZEFubm95TW5EaWZmVmFyc0NvblBlcm1pbXBQdHYuc3ZnIikNCiAgDQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBZEFubm95TW5EaWZmVmFyc0NvblBlcm1pbXBQdHYucGRmIiwgd2lkdGg9OCwgaGVpZ2h0PTgsIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJwZGYiKSkNCiAgdW5saW5rKCJQdEFkQW5ub3lNbkRpZmZWYXJzQ29uUGVybWltcFB0di5wZGYiKQ0KfQ0KDQpgYGANCg0KU2VsZWN0ZWQgbWV0cmljDQoNCmBgYHtyfQ0KDQpkaWZmVmFyIDwtICJFUE5MTEFGNTBkaWZmIg0KDQpgYGANCg0KIyMjIGRTUU0gYW5hbHlzaXMNCg0KVGhlIGFtYmllbnQtb25seSBzdGltdWxpIGFyZSBOT1QgcmVwbGFjZWQgaGVyZSwgYXMgdGhlIGRpZmZlcmVuY2UgYW5hbHlzaXMgaW5jbHVkZXMgZEIgbWV0cmljcy4NCg0KIyMjIyBJbmRpdmlkdWFsIFNRTXMNCg0KIyMjIyMgZFNoYXJwbmVzcw0KDQojIyMjIyMgU2V0IHZhcmlhYmxlcw0KDQpgYGB7cn0NCg0KaVZhcnMgPC0gYyhkaWZmVmFyLCAiZFNoYXJwQXVySVNPM1Bvd0F2Z01heExSIiwgImRTaGFycEF1cklTTzMwNUV4TWF4TFIiLCAiZFNoYXJwQXVyU0hNUG93QXZnTWF4TFIiLCAiZFNoYXJwQXVyU0hNMDVFeE1heExSIikNCmRWYXIgPC0gImRBbm5veU1lYW4iDQoNCnNlZWRzIDwtIGMoODQxOTQsIDkwNSwgNjQ4MTUsIDkyODA1NCwgNjI1MDkxKQ0KDQpgYGANCg0KIyMjIyMjIEh5cGVycGFyYW1ldGVyIHR1bmluZw0KDQpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTR9DQoNCnAgPC0gbXRyeVR1bmUoZGF0YUluPXN0aW1EYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZD1zZWVkc1sxXSwNCiAgICAgICAgICAgICBudHJlZXM9bnRyZWVzLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCnANCg0KYGBgDQoNClNlbGVjdGVkIGh5cGVycGFyYW1ldGVycw0KDQpgYGB7cn0NCg0KbnRyZWUgPC0gMjUwMQ0KbXRyeSA8LSBhcy5pbnRlZ2VyKGxlbmd0aChpVmFycykvMS4yNSkNCg0KYGBgDQoNCiMjIyMjIyBSdW4gbW9kZWwNCg0KVHJhaW4gcHJlbGltaW5hcnkgbW9kZWwNCg0KYGBge3J9DQoNCm5wZXJtIDwtIDUNCg0KcmVzdWx0c091dFNoYXJwIDwtIGNyZlJlZyhkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkc1sxOjJdLCBudHJlZT1udHJlZSwgbXRyeT1tdHJ5LCBwZXJtSW1wQ29uZFRocmVzPXBlcm1JbXBDb25kVGhyZXMsIG5wZXJtPW5wZXJtLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCg0KIyBwcmludCBtb2RlbCBwcmVkaWN0aW9uIHJlc3VsdHMNCnJlc3VsdHNPdXRTaGFycCRPT0JfUk1TRQ0KcmVzdWx0c091dFNoYXJwJE9PQl9NQUUNCnJlc3VsdHNPdXRTaGFycCRSc3F1YXJlZA0KDQpgYGANCg0KVHJhaW4gbXVsdGlwbGUgc2VlZHMgbW9kZWwNCg0KYGBge3J9DQoNCnJlc3VsdHNPdXRTaGFycCA8LSBtdWx0aV9jcmZSZWcoZGF0YUluPXN0aW1EYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHMsIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dFNoYXJwJE9PQl9STVNFDQpyZXN1bHRzT3V0U2hhcnAkT09CX01BRQ0KcmVzdWx0c091dFNoYXJwJFJzcXVhcmVkDQoNCmBgYA0KDQoNCmBgYHtyfQ0KIyBzdG9yZSByZXN1bHRzDQpyZXNkQW5ub3lNbkZpdFsnRGlmZiBzaGFycCcsICdSTVNFJ10gPC0gcmVzdWx0c091dFNoYXJwJE9PQl9STVNFDQpyZXNkQW5ub3lNbkZpdFsnRGlmZiBzaGFycCcsICdNQUUnXSA8LSByZXN1bHRzT3V0U2hhcnAkT09CX01BRQ0KcmVzZEFubm95TW5GaXRbJ0RpZmYgc2hhcnAnLCAnUnNxdWFyZWQnXSA8LSByZXN1bHRzT3V0U2hhcnAkUnNxdWFyZWQNCnJlc2RBbm5veU1uUGVybUltcCREaWZmU2hhcnAgPC0gcmVzdWx0c091dFNoYXJwJGNvbmRpdGlvbmFsX3Blcm1pbXANCg0KYGBgDQoNCiMjIyMjIyBQbG90IHJlc3VsdHMNCg0KYGBge3IsIGZpZy53aWR0aD04LGZpZy5oZWlnaHQ9Mi42fQ0KcGFyKG1haT1jKDAsMywwLDApKQ0KDQojIHBsb3QgY29uZGl0aW9uYWwgaW1wb3J0YW5jZQ0KcmVzdWx0c091dFNoYXJwLmNvbmltcCA8LSBhcnJhbmdlKHJlc3VsdHNPdXRTaGFycCRjb25kaXRpb25hbF9wZXJtaW1wLCBkZXNjKHJvd19udW1iZXIoKSkpDQoNCnBCYXIgPC0gZ2dwbG90KHJlc3VsdHNPdXRTaGFycC5jb25pbXApICsgZ2VvbV9jb2woYWVzKHg9ZmFjdG9yKHJvd25hbWVzKHJlc3VsdHNPdXRTaGFycC5jb25pbXApLCBsZXZlbHM9cm93bmFtZXMocmVzdWx0c091dFNoYXJwLmNvbmltcCkpLCB5PUNvbmRQZXJtSW1wKSwgZmlsbD1teWNvbG91cnNbMl0sIHdpZHRoPTAuNSkgKyBsYWJzKHg9IlZhcmlhYmxlIiwgeT0iQ29uZGl0aW9uYWwgdmFyaWFibGUgcGVybXV0YXRpb24gaW1wb3J0YW5jZSAobWVhbiBjaGFuZ2UgaW4gYW5ub3lhbmNlKSIpICsgZ2d0aXRsZSgiZFNoYXJwbmVzcyIpICsgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2VyaWYiKSwgcGFuZWwuZ3JpZD1lbGVtZW50X2xpbmUoY29sb3IgPSByZ2IoMjM1LCAyMzUsIDIzNSwgMTAwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgbGluZXdpZHRoID0gMC4yNSwgbGluZXR5cGUgPSAyKSkgKyBjb29yZF9mbGlwKCkNCnBCYXINCg0KaWYgKHNhdmVwbG90cyl7DQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBZEFubm95TW5kU2hhcnBDb25QZXJtaW1wLnN2ZyIsIHdpZHRoPTgsIGhlaWdodD0yLjYsIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJzdmciKSkNCiAgdW5saW5rKCJQdEFkQW5ub3lNbmRTaGFycENvblBlcm1pbXAuc3ZnIikNCiAgDQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBZEFubm95TW5kU2hhcnBDb25QZXJtaW1wLnBkZiIsIHdpZHRoPTgsIGhlaWdodD0yLjYsIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJwZGYiKSkNCiAgdW5saW5rKCJQdEFkQW5ub3lNbmRTaGFycENvblBlcm1pbXAucGRmIikNCn0NCg0KDQpgYGANCg0KU2VsZWN0ZWQgbWV0cmljDQoNCmBgYHtyfQ0KDQpkU2hhcnBWYXIgPC0gImRTaGFycEF1cklTTzNQb3dBdmdNYXhMUiINCg0KYGBgDQoNCiMjIyMjIGRUb25hbCBsb3VkbmVzcyBhbmQgZHRvbmFsaXR5DQoNCiMjIyMjIyBTZXQgdmFyaWFibGVzDQoNCmBgYHtyfQ0KDQppVmFycyA8LSBjKGRpZmZWYXIsICJkVG9uYWxFQ01BQXZnTWF4TFIiLCAiZFRvbmFsU0hNSW50MDVFeE1heExSIiwgImRUb25hbFNITUludEF2Z01heExSIiwgImRUb25hbEVDTUEwNUV4TWF4TFIiLCAiZFRvbkxkRUNNQVBvd0F2Z0JpbiIsICJkVG9uTGRFQ01BMDVFeEJpbiIpDQpkVmFyIDwtICJkQW5ub3lNZWFuIg0KDQpzZWVkcyA8LSBjKDU2MTY4NCwgMTA0Nzk4LCAxNTM2LCA0OCwgNDg1NjEpDQoNCmBgYA0KDQojIyMjIyMgSHlwZXJwYXJhbWV0ZXIgdHVuaW5nDQoNCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NH0NCg0KcCA8LSBtdHJ5VHVuZShkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkPXNlZWRzWzFdLA0KICAgICAgICAgICAgIG50cmVlcz1udHJlZXMsIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KcA0KDQpgYGANCg0KU2VsZWN0ZWQgaHlwZXJwYXJhbWV0ZXJzDQoNCmBgYHtyfQ0KDQpudHJlZSA8LSAxNTAxDQptdHJ5IDwtIGFzLmludGVnZXIobGVuZ3RoKGlWYXJzKS8xLjI1KQ0KDQpgYGANCg0KIyMjIyMjIFJ1biBtb2RlbA0KDQpUcmFpbiBwcmVsaW1pbmFyeSBtb2RlbA0KDQpgYGB7cn0NCiMgVG9uYWxpdHkgd2l0aCB0b25hbCBsb3VkbmVzcw0KDQpucGVybSA8LSA1DQoNCnJlc3VsdHNPdXRUb25hbDEgPC0gY3JmUmVnKGRhdGFJbj1zdGltRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzWzE6Ml0sIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dFRvbmFsMSRPT0JfUk1TRQ0KcmVzdWx0c091dFRvbmFsMSRPT0JfTUFFDQpyZXN1bHRzT3V0VG9uYWwxJFJzcXVhcmVkDQpgYGANClRyYWluIG11bHRpcGxlIHNlZWRzIG1vZGVsDQoNCmBgYHtyfQ0KIyBUb25hbGl0eSB3aXRoIHRvbmFsIGxvdWRuZXNzDQoNCnJlc3VsdHNPdXRUb25hbDEgPC0gbXVsdGlfY3JmUmVnKGRhdGFJbj1zdGltRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzLCBudHJlZT1udHJlZSwgbXRyeT1tdHJ5LCBwZXJtSW1wQ29uZFRocmVzPXBlcm1JbXBDb25kVGhyZXMsIG5wZXJtPW5wZXJtLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCg0KIyBwcmludCBtb2RlbCBwcmVkaWN0aW9uIHJlc3VsdHMNCnJlc3VsdHNPdXRUb25hbDEkT09CX1JNU0UNCnJlc3VsdHNPdXRUb25hbDEkT09CX01BRQ0KcmVzdWx0c091dFRvbmFsMSRSc3F1YXJlZA0KDQpgYGANCg0KYGBge3J9DQojIHN0b3JlIHJlc3VsdHMNCnJlc2RBbm5veU1uRml0WydEaWZmIHRvbmFsIGluYyBsb3VkJywgJ1JNU0UnXSA8LSByZXN1bHRzT3V0VG9uYWwxJE9PQl9STVNFDQpyZXNkQW5ub3lNbkZpdFsnRGlmZiB0b25hbCBpbmMgbG91ZCcsICdNQUUnXSA8LSByZXN1bHRzT3V0VG9uYWwxJE9PQl9NQUUNCnJlc2RBbm5veU1uRml0WydEaWZmIHRvbmFsIGluYyBsb3VkJywgJ1JzcXVhcmVkJ10gPC0gcmVzdWx0c091dFRvbmFsMSRSc3F1YXJlZA0KcmVzZEFubm95TW5QZXJtSW1wJERpZmZUb25hbDEgPC0gcmVzdWx0c091dFRvbmFsMSRjb25kaXRpb25hbF9wZXJtaW1wDQoNCmBgYA0KDQojIyMjIyMgUGxvdCByZXN1bHRzDQoNCmBgYHtyLCBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTIuNn0NCg0KcGFyKG1haT1jKDAsMywwLDApKQ0KDQojIHBsb3QgY29uZGl0aW9uYWwgaW1wb3J0YW5jZQ0KcmVzdWx0c091dFRvbmFsMS5jb25pbXAgPC0gYXJyYW5nZShyZXN1bHRzT3V0VG9uYWwxJGNvbmRpdGlvbmFsX3Blcm1pbXAsIGRlc2Mocm93X251bWJlcigpKSkNCg0KcEJhciA8LSBnZ3Bsb3QocmVzdWx0c091dFRvbmFsMS5jb25pbXApICsgZ2VvbV9jb2woYWVzKHg9ZmFjdG9yKHJvd25hbWVzKHJlc3VsdHNPdXRUb25hbDEuY29uaW1wKSwgbGV2ZWxzPXJvd25hbWVzKHJlc3VsdHNPdXRUb25hbDEuY29uaW1wKSksIHk9Q29uZFBlcm1JbXApLCBmaWxsPW15Y29sb3Vyc1szXSwgd2lkdGg9MC41KSArIGxhYnMoeD0iVmFyaWFibGUiLCB5PSJDb25kaXRpb25hbCB2YXJpYWJsZSBwZXJtdXRhdGlvbiBpbXBvcnRhbmNlIChtZWFuIGNoYW5nZSBpbiBhbm5veWFuY2UpIikgKyBnZ3RpdGxlKCJkVG9uYWxpdHkgaW5jLiBkdG9uYWwgbG91ZG5lc3MiKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiksIHBhbmVsLmdyaWQ9ZWxlbWVudF9saW5lKGNvbG9yID0gcmdiKDIzNSwgMjM1LCAyMzUsIDEwMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksIGxpbmV3aWR0aCA9IDAuMjUsIGxpbmV0eXBlID0gMikpICsgY29vcmRfZmxpcCh5bGltPWMoMCwgMS42KSkNCnBCYXINCg0KaWYgKHNhdmVwbG90cyl7DQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBZEFubm95TW5kVG9uYWxMZENvblBlcm1pbXAuc3ZnIiwgd2lkdGg9OCwgaGVpZ2h0PTIuNiwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInN2ZyIpKQ0KICB1bmxpbmsoIlB0QWRBbm5veU1uZFRvbmFsTGRDb25QZXJtaW1wLnN2ZyIpDQogIA0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWRBbm5veU1uZFRvbmFsTGRDb25QZXJtaW1wLnBkZiIsIHdpZHRoPTgsIGhlaWdodD0yLjYsIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJwZGYiKSkNCiAgdW5saW5rKCJQdEFkQW5ub3lNbmRUb25hbExkQ29uUGVybWltcC5wZGYiKQ0KfQ0KDQpgYGANCg0KU2VsZWN0ZWQgbWV0cmljDQoNCmBgYHtyfQ0KDQpkVG9uTGRWYXIgPC0gImRUb25MZEVDTUFQb3dBdmdCaW4iDQoNCmBgYA0KDQojIyMjIyBkVG9uYWxpdHkgd2l0aG91dCBkdG9uYWwgbG91ZG5lc3MNCg0KIyMjIyMjIFNldCB2YXJpYWJsZXMNCg0KYGBge3J9DQoNCmlWYXJzIDwtIGMoZGlmZlZhciwgImRUb25hbEVDTUFBdmdNYXhMUiIsICJkVG9uYWxTSE1JbnQwNUV4TWF4TFIiLCAiZFRvbmFsU0hNSW50QXZnTWF4TFIiLCAiZFRvbmFsRUNNQTA1RXhNYXhMUiIpDQpkVmFyIDwtICJkQW5ub3lNZWFuIg0KDQpzZWVkcyA8LSBjKDQxMDg2NSwgMjk1NCwgNzA4MTIsIDIwMywgNzk4NCkNCg0KYGBgDQoNCiMjIyMjIyBIeXBlcnBhcmFtZXRlciB0dW5pbmcNCg0KYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD00fQ0KDQpwIDwtIG10cnlUdW5lKGRhdGFJbj1zdGltRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWQ9c2VlZHNbMV0sDQogICAgICAgICAgICAgbnRyZWVzPW50cmVlcywgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQpwDQoNCmBgYA0KDQpTZWxlY3RlZCBoeXBlcnBhcmFtZXRlcnMNCg0KYGBge3J9DQoNCm50cmVlIDwtIDQwMDENCm10cnkgPC0gYXMuaW50ZWdlcihsZW5ndGgoaVZhcnMpLzEuMjUpDQoNCmBgYA0KDQojIyMjIyMgUnVuIG1vZGVsDQoNClRyYWluIHByZWxpbWluYXJ5IG1vZGVsDQoNCmBgYHtyfQ0KIyBUb25hbGl0eQ0KDQpucGVybSA8LSA1DQoNCnJlc3VsdHNPdXRUb25hbDIgPC0gY3JmUmVnKGRhdGFJbj1zdGltRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzWzE6Ml0sIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dFRvbmFsMiRPT0JfUk1TRQ0KcmVzdWx0c091dFRvbmFsMiRPT0JfTUFFDQpyZXN1bHRzT3V0VG9uYWwyJFJzcXVhcmVkDQoNCmBgYA0KDQpUcmFpbiBtdWx0aXBsZSBzZWVkcyBtb2RlbA0KDQpgYGB7cn0NCiMgVG9uYWxpdHkNCg0KcmVzdWx0c091dFRvbmFsMiA8LSBtdWx0aV9jcmZSZWcoZGF0YUluPXN0aW1EYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHMsIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dFRvbmFsMiRPT0JfUk1TRQ0KcmVzdWx0c091dFRvbmFsMiRPT0JfTUFFDQpyZXN1bHRzT3V0VG9uYWwyJFJzcXVhcmVkDQoNCmBgYA0KDQoNCmBgYHtyfQ0KDQojIHN0b3JlIHJlc3VsdHMNCnJlc2RBbm5veU1uRml0WydEaWZmIHRvbmFsIG5vIGxvdWQnLCAnUk1TRSddIDwtIHJlc3VsdHNPdXRUb25hbDIkT09CX1JNU0UNCnJlc2RBbm5veU1uRml0WydEaWZmIHRvbmFsIG5vIGxvdWQnLCAnTUFFJ10gPC0gcmVzdWx0c091dFRvbmFsMiRPT0JfTUFFDQpyZXNkQW5ub3lNbkZpdFsnRGlmZiB0b25hbCBubyBsb3VkJywgJ1JzcXVhcmVkJ10gPC0gcmVzdWx0c091dFRvbmFsMiRSc3F1YXJlZA0KcmVzZEFubm95TW5QZXJtSW1wJERpZmZUb25hbDIgPC0gcmVzdWx0c091dFRvbmFsMiRjb25kaXRpb25hbF9wZXJtaW1wDQoNCmBgYA0KDQojIyMjIyMgUGxvdCByZXN1bHRzDQoNCmBgYHtyLCBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTJ9DQpwYXIobWFpPWMoMCwzLDAsMCkpDQoNCiMgcGxvdCBjb25kaXRpb25hbCBpbXBvcnRhbmNlDQpyZXN1bHRzT3V0VG9uYWwyLmNvbmltcCA8LSBhcnJhbmdlKHJlc3VsdHNPdXRUb25hbDIkY29uZGl0aW9uYWxfcGVybWltcCwgZGVzYyhyb3dfbnVtYmVyKCkpKQ0KDQpwQmFyIDwtIGdncGxvdChyZXN1bHRzT3V0VG9uYWwyLmNvbmltcCkgKyBnZW9tX2NvbChhZXMoeD1mYWN0b3Iocm93bmFtZXMocmVzdWx0c091dFRvbmFsMi5jb25pbXApLCBsZXZlbHM9cm93bmFtZXMocmVzdWx0c091dFRvbmFsMi5jb25pbXApKSwgeT1Db25kUGVybUltcCksIGZpbGw9bXljb2xvdXJzWzNdLCB3aWR0aD0wLjUpICsgbGFicyh4PSJWYXJpYWJsZSIsIHk9IkNvbmRpdGlvbmFsIHZhcmlhYmxlIHBlcm11dGF0aW9uIGltcG9ydGFuY2UgKG1lYW4gY2hhbmdlIGluIGFubm95YW5jZSkiKSArIGdndGl0bGUoImRUb25hbGl0eSB3L28gdG9uYWwgbG91ZG5lc3MiKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiksIHBhbmVsLmdyaWQ9ZWxlbWVudF9saW5lKGNvbG9yID0gcmdiKDIzNSwgMjM1LCAyMzUsIDEwMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksIGxpbmV3aWR0aCA9IDAuMjUsIGxpbmV0eXBlID0gMikpICsgY29vcmRfZmxpcCh5bGltPWMoMCwgMS42KSkNCnBCYXINCg0KaWYgKHNhdmVwbG90cyl7DQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBZEFubm95TW5kVG9uYWxDb25QZXJtaW1wLnN2ZyIsIHdpZHRoPTgsIGhlaWdodD0yLCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAic3ZnIikpDQogIHVubGluaygiUHRBZEFubm95TW5kVG9uYWxDb25QZXJtaW1wLnN2ZyIpDQogIA0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWRBbm5veU1uZFRvbmFsQ29uUGVybWltcC5wZGYiLCB3aWR0aD04LCBoZWlnaHQ9MiwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInBkZiIpKQ0KICB1bmxpbmsoIlB0QWRBbm5veU1uZFRvbmFsQ29uUGVybWltcC5wZGYiKQ0KfQ0KDQoNCmBgYA0KDQpTZWxlY3RlYyBtZXRyaWMNCg0KYGBge3J9DQoNCmRUb25hbFZhciA8LSAiZFRvbmFsU0hNSW50QXZnTWF4TFIiDQoNCmBgYA0KDQojIyMjIyBkRmx1Y3R1YXRpb24gc3RyZW5ndGgNCg0KIyMjIyMjIFNldCB2YXJpYWJsZXMNCg0KYGBge3J9DQoNCiMgRmx1Y3R1YXRpb24gc3RyZW5ndGgNCmlWYXJzIDwtIGMoZGlmZlZhciwgImRGbHVjdFNITTEwRXhCaW4iLCAiZEZsdWN0U0hNMDVFeEJpbiIsICJkRmx1Y3RPVjEwRXhNYXhMUiIsICJkRmx1Y3RPVjA1RXhNYXhMUiIpDQpkVmFyIDwtICJkQW5ub3lNZWFuIg0KDQpzZWVkcyA8LSBjKDQxODY1NywgODQsIDE2MzAsIDE4NjU5LCAzNjg3KQ0KDQpgYGANCg0KDQojIyMjIyMgSHlwZXJwYXJhbWV0ZXIgdHVuaW5nDQoNCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NH0NCg0KcCA8LSBtdHJ5VHVuZShkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkPXNlZWRzWzFdLA0KICAgICAgICAgICAgIG50cmVlcz1udHJlZXMsIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KcA0KDQpgYGANCg0KU2VsZWN0ZWQgaHlwZXJwYXJhbWV0ZXJzDQoNCmBgYHtyfQ0KDQpudHJlZSA8LSAxMDAxDQptdHJ5IDwtIGFzLmludGVnZXIobGVuZ3RoKGlWYXJzKS8xLjI1KQ0KDQpgYGANCg0KIyMjIyMjIFJ1biBtb2RlbA0KDQpUcmFpbiBwcmVsaW1pbmFyeSBtb2RlbA0KDQpgYGB7cn0NCg0KbnBlcm0gPC0gNQ0KDQpyZXN1bHRzT3V0Rmx1Y3QgPC0gY3JmUmVnKGRhdGFJbj1zdGltRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzWzE6Ml0sIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dEZsdWN0JE9PQl9STVNFDQpyZXN1bHRzT3V0Rmx1Y3QkT09CX01BRQ0KcmVzdWx0c091dEZsdWN0JFJzcXVhcmVkDQoNCmBgYA0KVHJhaW4gbXVsdGlwbGUgc2VlZHMgbW9kZWwNCg0KYGBge3J9DQoNCnJlc3VsdHNPdXRGbHVjdCA8LSBtdWx0aV9jcmZSZWcoZGF0YUluPXN0aW1EYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHMsIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dEZsdWN0JE9PQl9STVNFDQpyZXN1bHRzT3V0Rmx1Y3QkT09CX01BRQ0KcmVzdWx0c091dEZsdWN0JFJzcXVhcmVkDQoNCmBgYA0KDQoNCmBgYHtyfQ0KDQojIHN0b3JlIHJlc3VsdHMNCnJlc2RBbm5veU1uRml0WydEaWZmIGZsdWN0JywgJ1JNU0UnXSA8LSByZXN1bHRzT3V0Rmx1Y3QkT09CX1JNU0UNCnJlc2RBbm5veU1uRml0WydEaWZmIGZsdWN0JywgJ01BRSddIDwtIHJlc3VsdHNPdXRGbHVjdCRPT0JfTUFFDQpyZXNkQW5ub3lNbkZpdFsnRGlmZiBmbHVjdCcsICdSc3F1YXJlZCddIDwtIHJlc3VsdHNPdXRGbHVjdCRSc3F1YXJlZA0KcmVzZEFubm95TW5QZXJtSW1wJERpZmZGbHVjdCA8LSByZXN1bHRzT3V0Rmx1Y3QkY29uZGl0aW9uYWxfcGVybWltcA0KDQpgYGANCg0KIyMjIyMjIFBsb3QgcmVzdWx0cw0KDQpgYGB7ciwgZmlnLndpZHRoPTgsZmlnLmhlaWdodD0yfQ0KcGFyKG1haT1jKDAsMywwLDApKQ0KDQojIHBsb3QgY29uZGl0aW9uYWwgaW1wb3J0YW5jZQ0KcmVzdWx0c091dEZsdWN0LmNvbmltcCA8LSBhcnJhbmdlKHJlc3VsdHNPdXRGbHVjdCRjb25kaXRpb25hbF9wZXJtaW1wLCBkZXNjKHJvd19udW1iZXIoKSkpDQoNCnBCYXIgPC0gZ2dwbG90KHJlc3VsdHNPdXRGbHVjdC5jb25pbXApICsgZ2VvbV9jb2woYWVzKHg9ZmFjdG9yKHJvd25hbWVzKHJlc3VsdHNPdXRGbHVjdC5jb25pbXApLCBsZXZlbHM9cm93bmFtZXMocmVzdWx0c091dEZsdWN0LmNvbmltcCkpLCB5PUNvbmRQZXJtSW1wKSwgZmlsbD1teWNvbG91cnNbNF0sIHdpZHRoPTAuNSkgKyBsYWJzKHg9IlZhcmlhYmxlIiwgeT0iQ29uZGl0aW9uYWwgdmFyaWFibGUgcGVybXV0YXRpb24gaW1wb3J0YW5jZSAobWVhbiBjaGFuZ2UgaW4gYW5ub3lhbmNlKSIpICsgZ2d0aXRsZSgiZEZsdWN0dWF0aW9uIHN0cmVuZ3RoIikgKyB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIpLCBwYW5lbC5ncmlkPWVsZW1lbnRfbGluZShjb2xvciA9IHJnYigyMzUsIDIzNSwgMjM1LCAxMDAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCBsaW5ld2lkdGggPSAwLjI1LCBsaW5ldHlwZSA9IDIpKSArIGNvb3JkX2ZsaXAoKQ0KcEJhcg0KDQppZiAoc2F2ZXBsb3RzKXsNCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFkQW5ub3lNbmRGbHVjdENvblBlcm1pbXAuc3ZnIiwgd2lkdGg9OCwgaGVpZ2h0PTIsIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJzdmciKSkNCiAgdW5saW5rKCJQdEFkQW5ub3lNbkZsdWN0Q29uUGVybWltcC5zdmciKQ0KICANCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFkQW5ub3lNbmRGbHVjdENvblBlcm1pbXAucGRmIiwgd2lkdGg9OCwgaGVpZ2h0PTIsIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJwZGYiKSkNCiAgdW5saW5rKCJQdEFkQW5ub3lNbkZsdWN0Q29uUGVybWltcC5wZGYiKQ0KfQ0KDQpgYGANCg0KU2VsZWN0ZWQgbWV0cmljDQoNCmBgYHtyfQ0KDQpkRmx1Y3RWYXIgPC0gImRGbHVjdE9WMTBFeE1heExSIg0KDQpgYGANCg0KDQojIyMjIyBkUm91Z2huZXNzDQoNCiMjIyMjIyBTZXQgdmFyaWFibGVzDQoNCmBgYHtyfQ0KDQojIFJvdWdobmVzcw0KaVZhcnMgPC0gYyhkaWZmVmFyLCAiZFJvdWdoRUNNQTEwRXhCaW4iLCAiZFJvdWdoRUNNQTA1RXhCaW4iLCAiZFJvdWdoRloxMEV4TWF4TFIiLCAiZFJvdWdoRlowNUV4TWF4TFIiKQ0KZFZhciA8LSAiZEFubm95TWVhbiINCg0Kc2VlZHMgPC0gYyg2OTg1MSwgODUxMDksIDQxMDk4NiwgMTU2MywgODk2KQ0KDQpgYGANCg0KIyMjIyMjIEh5cGVycGFyYW1ldGVyIHR1bmluZw0KDQpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTR9DQoNCnAgPC0gbXRyeVR1bmUoZGF0YUluPXN0aW1EYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZD1zZWVkc1sxXSwNCiAgICAgICAgICAgICBudHJlZXM9bnRyZWVzLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCnANCg0KYGBgDQoNClNlbGVjdGVkIGh5cGVycGFyYW1ldGVycw0KDQpgYGB7cn0NCg0KbnRyZWUgPC0gMTUwMQ0KbXRyeSA8LSBhcy5pbnRlZ2VyKGxlbmd0aChpVmFycykvMS4yNSkNCg0KYGBgDQoNCiMjIyMjIyBSdW4gbW9kZWwNCg0KVHJhaW4gcHJlbGltaW5hcnkgbW9kZWwNCg0KYGBge3J9DQoNCm5wZXJtIDwtIDUNCg0KcmVzdWx0c091dFJvdWdoIDwtIGNyZlJlZyhkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkc1sxOjJdLCBudHJlZT1udHJlZSwgbXRyeT1tdHJ5LCBwZXJtSW1wQ29uZFRocmVzPXBlcm1JbXBDb25kVGhyZXMsIG5wZXJtPW5wZXJtLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCg0KIyBwcmludCBtb2RlbCBwcmVkaWN0aW9uIHJlc3VsdHMNCnJlc3VsdHNPdXRSb3VnaCRPT0JfUk1TRQ0KcmVzdWx0c091dFJvdWdoJE9PQl9NQUUNCnJlc3VsdHNPdXRSb3VnaCRSc3F1YXJlZA0KDQpgYGANCg0KVHJhaW4gbXVsdGlwbGUgc2VlZHMgbW9kZWwNCg0KYGBge3J9DQoNCnJlc3VsdHNPdXRSb3VnaCA8LSBtdWx0aV9jcmZSZWcoZGF0YUluPXN0aW1EYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHMsIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dFJvdWdoJE9PQl9STVNFDQpyZXN1bHRzT3V0Um91Z2gkT09CX01BRQ0KcmVzdWx0c091dFJvdWdoJFJzcXVhcmVkDQoNCmBgYA0KDQpgYGB7cn0NCiMgc3RvcmUgcmVzdWx0cw0KcmVzZEFubm95TW5GaXRbJ0RpZmYgcm91Z2gnLCAnUk1TRSddIDwtIHJlc3VsdHNPdXRSb3VnaCRPT0JfUk1TRQ0KcmVzZEFubm95TW5GaXRbJ0RpZmYgcm91Z2gnLCAnTUFFJ10gPC0gcmVzdWx0c091dFJvdWdoJE9PQl9NQUUNCnJlc2RBbm5veU1uRml0WydEaWZmIHJvdWdoJywgJ1JzcXVhcmVkJ10gPC0gcmVzdWx0c091dFJvdWdoJFJzcXVhcmVkDQpyZXNkQW5ub3lNblBlcm1JbXAkRGlmZlJvdWdoIDwtIHJlc3VsdHNPdXRSb3VnaCRjb25kaXRpb25hbF9wZXJtaW1wDQoNCmBgYA0KDQojIyMjIyMgUGxvdCByZXN1bHRzDQoNCmBgYHtyLCBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTJ9DQpwYXIobWFpPWMoMCwzLDAsMCkpDQoNCiMgcGxvdCBjb25kaXRpb25hbCBpbXBvcnRhbmNlDQpyZXN1bHRzT3V0Um91Z2guY29uaW1wIDwtIGFycmFuZ2UocmVzdWx0c091dFJvdWdoJGNvbmRpdGlvbmFsX3Blcm1pbXAsIGRlc2Mocm93X251bWJlcigpKSkNCg0KcEJhciA8LSBnZ3Bsb3QocmVzdWx0c091dFJvdWdoLmNvbmltcCkgKyBnZW9tX2NvbChhZXMoeD1mYWN0b3Iocm93bmFtZXMocmVzdWx0c091dFJvdWdoLmNvbmltcCksIGxldmVscz1yb3duYW1lcyhyZXN1bHRzT3V0Um91Z2guY29uaW1wKSksIHk9Q29uZFBlcm1JbXApLCBmaWxsPW15Y29sb3Vyc1s1XSwgd2lkdGg9MC41KSArIGxhYnMoeD0iVmFyaWFibGUiLCB5PSJDb25kaXRpb25hbCB2YXJpYWJsZSBwZXJtdXRhdGlvbiBpbXBvcnRhbmNlIChtZWFuIGNoYW5nZSBpbiBhbm5veWFuY2UpIikgKyBnZ3RpdGxlKCJkUm91Z2huZXNzIikgKyB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIpLCBwYW5lbC5ncmlkPWVsZW1lbnRfbGluZShjb2xvciA9IHJnYigyMzUsIDIzNSwgMjM1LCAxMDAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCBsaW5ld2lkdGggPSAwLjI1LCBsaW5ldHlwZSA9IDIpKSArIGNvb3JkX2ZsaXAoKQ0KcEJhcg0KDQppZiAoc2F2ZXBsb3RzKXsNCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFkQW5ub3lNbmRSb3VnaENvblBlcm1pbXAuc3ZnIiwgd2lkdGg9OCwgaGVpZ2h0PTIsIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJzdmciKSkNCiAgdW5saW5rKCJQdEFkQW5ub3lNbmRSb3VnaENvblBlcm1pbXAuc3ZnIikNCiAgDQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBZEFubm95TW5kUm91Z2hDb25QZXJtaW1wLnBkZiIsIHdpZHRoPTgsIGhlaWdodD0yLCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAicGRmIikpDQogIHVubGluaygiUHRBZEFubm95TW5kUm91Z2hDb25QZXJtaW1wLnBkZiIpDQp9DQoNCg0KYGBgDQoNClNlbGVjdGVkIG1ldHJpYw0KDQpgYGB7cn0NCg0KZFJvdWdoVmFyIDwtICJkUm91Z2hFQ01BMDVFeEJpbiINCg0KYGBgDQoNCiMjIyMjIGRJbXB1bHNpdmVuZXNzDQoNCiMjIyMjIyBTZXQgdmFyaWFibGVzDQoNCmBgYHtyfQ0KIyBJbXB1bHNpdmVuZXNzDQppVmFycyA8LSBjKGRpZmZWYXIsICJkSW1wdWxzU0hNQXZnTWF4TFIiLCAiZEltcHVsc1NITTA1RXhNYXhMUiIsICJkSW1wdWxzU0hNUG93QXZnTWF4TFIiKQ0KZFZhciA8LSAiZEFubm95TWVhbiINCg0Kc2VlZHMgPC0gYyg0MTg2NTksIDc4MDUsIDM4NDc1LCA2NTgzNCwgMTY1MykNCg0KYGBgDQoNCiMjIyMjIyBIeXBlcnBhcmFtZXRlciB0dW5pbmcNCg0KYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD00fQ0KDQpwIDwtIG10cnlUdW5lKGRhdGFJbj1zdGltRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWQ9c2VlZHNbMV0sDQogICAgICAgICAgICAgbnRyZWVzPW50cmVlcywgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQpwDQoNCmBgYA0KDQpTZWxlY3RlZCBoeXBlcnBhcmFtZXRlcnMNCg0KYGBge3J9DQoNCm50cmVlIDwtIDUwMQ0KbXRyeSA8LSBhcy5pbnRlZ2VyKGxlbmd0aChpVmFycykvMS4yNSkNCg0KYGBgDQoNCiMjIyMjIyBSdW4gbW9kZWwNCg0KVHJhaW4gcHJlbGltaW5hcnkgbW9kZWwNCg0KYGBge3J9DQoNCm5wZXJtIDwtIDUNCg0KcmVzdWx0c091dEltcHVscyA8LSBjcmZSZWcoZGF0YUluPXN0aW1EYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHNbMToyXSwgbnRyZWU9bnRyZWUsIG10cnk9bXRyeSwgcGVybUltcENvbmRUaHJlcz1wZXJtSW1wQ29uZFRocmVzLCBucGVybT1ucGVybSwgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQoNCiMgcHJpbnQgbW9kZWwgcHJlZGljdGlvbiByZXN1bHRzDQpyZXN1bHRzT3V0SW1wdWxzJE9PQl9STVNFDQpyZXN1bHRzT3V0SW1wdWxzJE9PQl9NQUUNCnJlc3VsdHNPdXRJbXB1bHMkUnNxdWFyZWQNCg0KYGBgDQoNClRyYWluIG11bHRpcGxlIHNlZWRzIG1vZGVsDQoNCmBgYHtyfQ0KDQpyZXN1bHRzT3V0SW1wdWxzIDwtIG11bHRpX2NyZlJlZyhkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkcywgbnRyZWU9bnRyZWUsIG10cnk9bXRyeSwgcGVybUltcENvbmRUaHJlcz1wZXJtSW1wQ29uZFRocmVzLCBucGVybT1ucGVybSwgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQoNCiMgcHJpbnQgbW9kZWwgcHJlZGljdGlvbiByZXN1bHRzDQpyZXN1bHRzT3V0SW1wdWxzJE9PQl9STVNFDQpyZXN1bHRzT3V0SW1wdWxzJE9PQl9NQUUNCnJlc3VsdHNPdXRJbXB1bHMkUnNxdWFyZWQNCg0KYGBgDQoNCmBgYHtyfQ0KDQojIHN0b3JlIHJlc3VsdHMNCnJlc2RBbm5veU1uRml0WydEaWZmIGltcHVscycsICdSTVNFJ10gPC0gcmVzdWx0c091dEltcHVscyRPT0JfUk1TRQ0KcmVzZEFubm95TW5GaXRbJ0RpZmYgaW1wdWxzJywgJ01BRSddIDwtIHJlc3VsdHNPdXRJbXB1bHMkT09CX01BRQ0KcmVzZEFubm95TW5GaXRbJ0RpZmYgaW1wdWxzJywgJ1JzcXVhcmVkJ10gPC0gcmVzdWx0c091dEltcHVscyRSc3F1YXJlZA0KcmVzZEFubm95TW5QZXJtSW1wJERpZmZJbXB1bHMgPC0gcmVzdWx0c091dEltcHVscyRjb25kaXRpb25hbF9wZXJtaW1wDQoNCmBgYA0KDQojIyMjIyMgUGxvdCByZXN1bHRzDQoNCmBgYHtyLCBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTJ9DQpwYXIobWFpPWMoMCwzLDAsMCkpDQoNCiMgcGxvdCBjb25kaXRpb25hbCBpbXBvcnRhbmNlDQpyZXN1bHRzT3V0SW1wdWxzLmNvbmltcCA8LSBhcnJhbmdlKHJlc3VsdHNPdXRJbXB1bHMkY29uZGl0aW9uYWxfcGVybWltcCwgZGVzYyhyb3dfbnVtYmVyKCkpKQ0KDQpwQmFyIDwtIGdncGxvdChyZXN1bHRzT3V0SW1wdWxzLmNvbmltcCkgKyBnZW9tX2NvbChhZXMoeD1mYWN0b3Iocm93bmFtZXMocmVzdWx0c091dEltcHVscy5jb25pbXApLCBsZXZlbHM9cm93bmFtZXMocmVzdWx0c091dEltcHVscy5jb25pbXApKSwgeT1Db25kUGVybUltcCksIGZpbGw9bXljb2xvdXJzWzZdLCB3aWR0aD0wLjUpICsgbGFicyh4PSJWYXJpYWJsZSIsIHk9IkNvbmRpdGlvbmFsIHZhcmlhYmxlIHBlcm11dGF0aW9uIGltcG9ydGFuY2UgKG1lYW4gY2hhbmdlIGluIGFubm95YW5jZSkiKSArIGdndGl0bGUoImRJbXB1bHNpdmVuZXNzIikgKyB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIpLCBwYW5lbC5ncmlkPWVsZW1lbnRfbGluZShjb2xvciA9IHJnYigyMzUsIDIzNSwgMjM1LCAxMDAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCBsaW5ld2lkdGggPSAwLjI1LCBsaW5ldHlwZSA9IDIpKSArIGNvb3JkX2ZsaXAoKQ0KcEJhcg0KDQppZiAoc2F2ZXBsb3RzKXsNCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFkQW5ub3lNbmRJbXB1bHNDb25QZXJtaW1wLnN2ZyIsIHdpZHRoPTgsIGhlaWdodD0yLCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAic3ZnIikpDQogIHVubGluaygiUHRBZEFubm95TW5kSW1wdWxzQ29uUGVybWltcC5zdmciKQ0KICANCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFkQW5ub3lNbmRJbXB1bHNDb25QZXJtaW1wLnBkZiIsIHdpZHRoPTgsIGhlaWdodD0yLCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAicGRmIikpDQogIHVubGluaygiUHRBZEFubm95TW5kSW1wdWxzQ29uUGVybWltcC5wZGYiKQ0KfQ0KDQpgYGANCg0KU2VsZWN0ZWQgbWV0cmljDQoNCmBgYHtyfQ0KDQpkSW1wdWxzVmFyIDwtICJkSW1wdWxzU0hNMDVFeE1heExSIg0KDQpgYGANCg0KIyMjIyBkU1FNIGFuZCBsb3VkbmVzcyBjb21wYXJpc29uDQoNCk5vdyB0aGUgaGlnaGVzdCBpbXBvcnRhbmNlIGRTUU1zIGFyZSByYW5rZWQgYWdhaW5zdCBlYWNoIG90aGVyLCBjb250cm9sbGluZyBmb3IgbG91ZG5lc3MgZGlmZmVyZW5jZS4NCg0KIyMjIyMgSW5jbHVkZSBkdG9uYWwgbG91ZG5lc3MNCg0KIyMjIyMjIFNldCB2YXJpYWJsZXMNCg0KYGBge3J9DQoNCmlWYXJzIDwtIGMoZGlmZlZhciwgZFNoYXJwVmFyLCBkVG9uTGRWYXIsIGRGbHVjdFZhciwgZFJvdWdoVmFyLCBkSW1wdWxzVmFyKQ0KZFZhciA8LSAiZEFubm95TWVhbiINCg0Kc2VlZHMgPC0gYyg5ODQ2NSwgNTQxNjMsIDY1NDEsIDM2NDg1LCA4NDk2NzUpDQoNCmBgYA0KDQojIyMjIyMgSHlwZXJwYXJhbWV0ZXIgdHVuaW5nDQoNCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NH0NCg0KcCA8LSBtdHJ5VHVuZShkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkPXNlZWRzWzFdLA0KICAgICAgICAgICAgIG50cmVlcz1udHJlZXMsIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KcA0KDQpgYGANCg0KU2VsZWN0ZWQgaHlwZXJwYXJhbWV0ZXJzDQoNCmBgYHtyfQ0KDQpudHJlZSA8LSAyNTENCm10cnkgPC0gYXMuaW50ZWdlcihsZW5ndGgoaVZhcnMpLzEuNzUpDQoNCmBgYA0KDQojIyMjIyMgUnVuIG1vZGVsDQoNClRyYWluIHByZWxpbWluYXJ5IG1vZGVsDQoNCmBgYHtyfQ0KDQpucGVybSA8LSA1DQoNCnJlc3VsdHNPdXRTUU1zMSA8LSBjcmZSZWcoZGF0YUluPXN0aW1EYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHNbMToyXSwgbnRyZWU9bnRyZWUsIG10cnk9bXRyeSwgcGVybUltcENvbmRUaHJlcz1wZXJtSW1wQ29uZFRocmVzLCBucGVybT1ucGVybSwgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQoNCiMgcHJpbnQgbW9kZWwgcHJlZGljdGlvbiByZXN1bHRzDQpyZXN1bHRzT3V0U1FNczEkT09CX1JNU0UNCnJlc3VsdHNPdXRTUU1zMSRPT0JfTUFFDQpyZXN1bHRzT3V0U1FNczEkUnNxdWFyZWQNCg0KYGBgDQoNClRyYWluIG11bHRpcGxlIHNlZWRzIG1vZGVsDQoNCmBgYHtyfQ0KDQpyZXN1bHRzT3V0U1FNczEgPC0gbXVsdGlfY3JmUmVnKGRhdGFJbj1zdGltRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzLCBudHJlZT1udHJlZSwgbXRyeT1tdHJ5LCBwZXJtSW1wQ29uZFRocmVzPXBlcm1JbXBDb25kVGhyZXMsIG5wZXJtPW5wZXJtLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCg0KIyBwcmludCBtb2RlbCBwcmVkaWN0aW9uIHJlc3VsdHMNCnJlc3VsdHNPdXRTUU1zMSRPT0JfUk1TRQ0KcmVzdWx0c091dFNRTXMxJE9PQl9NQUUNCnJlc3VsdHNPdXRTUU1zMSRSc3F1YXJlZA0KDQpgYGANCg0KYGBge3J9DQoNCiMgc3RvcmUgcmVzdWx0cw0KcmVzZEFubm95TW5GaXRbJ0RpZmYgU1FNcyBpbmMgdG9uYWwgbG91ZCcsICdSTVNFJ10gPC0gcmVzdWx0c091dFNRTXMxJE9PQl9STVNFDQpyZXNkQW5ub3lNbkZpdFsnRGlmZiBTUU1zIGluYyB0b25hbCBsb3VkJywgJ01BRSddIDwtIHJlc3VsdHNPdXRTUU1zMSRPT0JfTUFFDQpyZXNkQW5ub3lNbkZpdFsnRGlmZiBTUU1zIGluYyB0b25hbCBsb3VkJywgJ1JzcXVhcmVkJ10gPC0gcmVzdWx0c091dFNRTXMxJFJzcXVhcmVkDQpyZXNkQW5ub3lNblBlcm1JbXAkRGlmZlNRTXMxIDwtIHJlc3VsdHNPdXRTUU1zMSRjb25kaXRpb25hbF9wZXJtaW1wDQoNCmBgYA0KDQojIyMjIyMgUGxvdCByZXN1bHRzDQoNCmBgYHtyLCBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTIuNH0NCnBhcihtYWk9YygwLDMsMCwwKSkNCg0KIyBwbG90IGNvbmRpdGlvbmFsIGltcG9ydGFuY2UNCnJlc3VsdHNPdXRTUU1zMS5jb25pbXAgPC0gYXJyYW5nZShyZXN1bHRzT3V0U1FNczEkY29uZGl0aW9uYWxfcGVybWltcCwgZGVzYyhyb3dfbnVtYmVyKCkpKQ0KDQpwQmFyIDwtIGdncGxvdChyZXN1bHRzT3V0U1FNczEuY29uaW1wKSArIGdlb21fY29sKGFlcyh4PWZhY3Rvcihyb3duYW1lcyhyZXN1bHRzT3V0U1FNczEuY29uaW1wKSwgbGV2ZWxzPXJvd25hbWVzKHJlc3VsdHNPdXRTUU1zMS5jb25pbXApKSwgeT1Db25kUGVybUltcCksIGZpbGw9bXljb2xvdXJzWzddLCB3aWR0aD0wLjUpICsgbGFicyh4PSJWYXJpYWJsZSIsIHk9IkNvbmRpdGlvbmFsIHZhcmlhYmxlIHBlcm11dGF0aW9uIGltcG9ydGFuY2UgKG1lYW4gY2hhbmdlIGluIGFubm95YW5jZSkiKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiksIHBhbmVsLmdyaWQ9ZWxlbWVudF9saW5lKGNvbG9yID0gcmdiKDIzNSwgMjM1LCAyMzUsIDEwMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksIGxpbmV3aWR0aCA9IDAuMjUsIGxpbmV0eXBlID0gMikpICsgY29vcmRfZmxpcCh5bGltPWMoMCwgMS4yKSkNCnBCYXINCg0KaWYgKHNhdmVwbG90cyl7DQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBZEFubm95TW5EaWZmU1FNc1RvbkxkQ29uUGVybWltcC5zdmciLCB3aWR0aD04LCBoZWlnaHQ9Mi40LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAic3ZnIikpDQogIHVubGluaygiUHRBZEFubm95TW5EaWZmU1FNc1RvbkxkQ29uUGVybWltcC5zdmciKQ0KICANCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFkQW5ub3lNbkRpZmZTUU1zVG9uTGRDb25QZXJtaW1wLnBkZiIsIHdpZHRoPTgsIGhlaWdodD0yLjQsIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJwZGYiKSkNCiAgdW5saW5rKCJQdEFkQW5ub3lNbkRpZmZTUU1zVG9uTGRDb25QZXJtaW1wLnBkZiIpDQp9DQoNCmBgYA0KDQojIyMjIyBFeGNsdWRlIHRvbmFsIGxvdWRuZXNzDQoNCiMjIyMjIyBTZXQgdmFyaWFibGVzDQoNCmBgYHtyfQ0KDQppVmFycyA8LSBjKGRpZmZWYXIsIGRTaGFycFZhciwgZFRvbmFsVmFyLCBkRmx1Y3RWYXIsIGRSb3VnaFZhciwgZEltcHVsc1ZhcikNCmRWYXIgPC0gImRBbm5veU1lYW4iDQoNCnNlZWRzIDwtIGMoNDk4NjUsIDc4NTIsIDg0NTk2MSwgNDEwNTgzLCAzNjc0OCkNCg0KYGBgDQoNCiMjIyMjIyBIeXBlcnBhcmFtZXRlciB0dW5pbmcNCg0KYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD00fQ0KDQpwIDwtIG10cnlUdW5lKGRhdGFJbj1zdGltRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWQ9c2VlZHNbMV0sDQogICAgICAgICAgICAgbnRyZWVzPW50cmVlcywgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQpwDQoNCmBgYA0KDQpTZWxlY3RlZCBoeXBlcnBhcmFtZXRlcnMNCg0KYGBge3J9DQoNCm50cmVlIDwtIDQwMDENCm10cnkgPC0gYXMuaW50ZWdlcihsZW5ndGgoaVZhcnMpLzEuNzUpDQoNCmBgYA0KDQoNCiMjIyMjIyBSdW4gbW9kZWwNCg0KVHJhaW4gcHJlbGltaW5hcnkgbW9kZWwNCg0KYGBge3J9DQoNCm5wZXJtIDwtIDUNCg0KcmVzdWx0c091dFNRTXMyIDwtIGNyZlJlZyhkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkc1sxOjJdLCBudHJlZT1udHJlZSwgbXRyeT1tdHJ5LCBwZXJtSW1wQ29uZFRocmVzPXBlcm1JbXBDb25kVGhyZXMsIG5wZXJtPW5wZXJtLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCg0KIyBwcmludCBtb2RlbCBwcmVkaWN0aW9uIHJlc3VsdHMNCnJlc3VsdHNPdXRTUU1zMiRPT0JfUk1TRQ0KcmVzdWx0c091dFNRTXMyJE9PQl9NQUUNCnJlc3VsdHNPdXRTUU1zMiRSc3F1YXJlZA0KDQpgYGANCg0KVHJhaW4gbXVsdGlwbGUgc2VlZHMgbW9kZWwNCg0KYGBge3J9DQoNCnJlc3VsdHNPdXRTUU1zMiA8LSBtdWx0aV9jcmZSZWcoZGF0YUluPXN0aW1EYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHMsIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dFNRTXMyJE9PQl9STVNFDQpyZXN1bHRzT3V0U1FNczIkT09CX01BRQ0KcmVzdWx0c091dFNRTXMyJFJzcXVhcmVkDQoNCmBgYA0KDQpgYGB7cn0NCg0KIyBzdG9yZSByZXN1bHRzDQpyZXNkQW5ub3lNbkZpdFsnRGlmZiBTUU1zIG5vIHRvbmFsIGxvdWQnLCAnUk1TRSddIDwtIHJlc3VsdHNPdXRTUU1zMiRPT0JfUk1TRQ0KcmVzZEFubm95TW5GaXRbJ0RpZmYgU1FNcyBubyB0b25hbCBsb3VkJywgJ1JNU0UnXSA8LSByZXN1bHRzT3V0U1FNczIkT09CX01BRQ0KcmVzZEFubm95TW5GaXRbJ0RpZmYgU1FNcyBubyB0b25hbCBsb3VkJywgJ1JzcXVhcmVkJ10gPC0gcmVzdWx0c091dFNRTXMyJFJzcXVhcmVkDQpyZXNkQW5ub3lNblBlcm1JbXAkRGlmZlNRTXMyIDwtIHJlc3VsdHNPdXRTUU1zMiRjb25kaXRpb25hbF9wZXJtaW1wDQoNCmBgYA0KDQojIyMjIyMgUGxvdCByZXN1bHRzDQoNCmBgYHtyLCBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTIuNH0NCnBhcihtYWk9YygwLDMsMCwwKSkNCg0KIyBwbG90IGNvbmRpdGlvbmFsIGltcG9ydGFuY2UNCnJlc3VsdHNPdXRTUU1zMi5jb25pbXAgPC0gYXJyYW5nZShyZXN1bHRzT3V0U1FNczIkY29uZGl0aW9uYWxfcGVybWltcCwgZGVzYyhyb3dfbnVtYmVyKCkpKQ0KDQpwQmFyIDwtIGdncGxvdChyZXN1bHRzT3V0U1FNczIuY29uaW1wKSArIGdlb21fY29sKGFlcyh4PWZhY3Rvcihyb3duYW1lcyhyZXN1bHRzT3V0U1FNczIuY29uaW1wKSwgbGV2ZWxzPXJvd25hbWVzKHJlc3VsdHNPdXRTUU1zMi5jb25pbXApKSwgeT1Db25kUGVybUltcCksIGZpbGw9bXljb2xvdXJzWzddLCB3aWR0aD0wLjUpICsgbGFicyh4PSJWYXJpYWJsZSIsIHk9IkNvbmRpdGlvbmFsIHZhcmlhYmxlIHBlcm11dGF0aW9uIGltcG9ydGFuY2UgKG1lYW4gY2hhbmdlIGluIGFubm95YW5jZSkiKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiksIHBhbmVsLmdyaWQ9ZWxlbWVudF9saW5lKGNvbG9yID0gcmdiKDIzNSwgMjM1LCAyMzUsIDEwMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksIGxpbmV3aWR0aCA9IDAuMjUsIGxpbmV0eXBlID0gMikpICsgY29vcmRfZmxpcCh5bGltPWMoMCwgMS4yKSkNCnBCYXINCg0KaWYgKHNhdmVwbG90cyl7DQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBZEFubm95TW5EaWZmU1FNc05vVG9uTGRDb25QZXJtaW1wLnN2ZyIsIHdpZHRoPTgsIGhlaWdodD0yLjQsIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJzdmciKSkNCiAgdW5saW5rKCJQdEFkQW5ub3lNbkRpZmZTUU1zTm9Ub25MZENvblBlcm1pbXAuc3ZnIikNCiAgDQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBZEFubm95TW5EaWZmU1FNc05vVG9uTGRDb25QZXJtaW1wLnBkZiIsIHdpZHRoPTgsIGhlaWdodD0yLjQsIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJwZGYiKSkNCiAgdW5saW5rKCJQdEFkQW5ub3lNbkRpZmZTUU1zTm9Ub25MZENvblBlcm1pbXAucGRmIikNCn0NCg0KYGBgDQoNCiMjIyBTYXZlIHRoZSByZXN1bHRzIG91dHB1dHMgdG8gZmlsZQ0KDQpgYGB7cn0NCg0KaWYgKHNhdmVkYXRhKXsNCiAgdXRpbHM6OndyaXRlLmNzdihyZXNkQW5ub3lNbkZpdCwgcGFzdGUob3V0RGF0YVBhdGgsICJcXHB0QUNSRmRBbm5veU1uT09CRml0LmNzdiIsIHNlcD0iIikpDQogIGlpIDwtIDANCiAgdGVtcCA9IGxpc3QoKQ0KICBmb3IgKHJlcyBpbiByZXNkQW5ub3lNblBlcm1JbXApew0KICAgIGlpIDwtIGlpICsgMQ0KICAgIHRlbXBbW2lpXV0gPC0gYXMuZGF0YS5mcmFtZShyZXNkQW5ub3lNblBlcm1JbXBbaWldKQ0KICAgIG5hbWVzKHRlbXBbW2lpXV0pIDwtIG5hbWVzKHJlc2RBbm5veU1uUGVybUltcFtpaV0pDQogIH0NCiAgb3Blbnhsc3g6OndyaXRlLnhsc3godGVtcCwgcGFzdGUob3V0RGF0YVBhdGgsICJcXHB0QUNSRmRBbm5veU1uQ29uUGVybWltcC54bHN4IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VwPSIiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgcm93TmFtZXM9VFJVRSkNCn0NCg0KYGBgDQoNCiMjIChDaGFuZ2UgdG8pIEhpZ2ggYW5ub3lhbmNlDQoNCkluaXRpYWxpc2UgcmVzdWx0cyBvdXRwdXQgdmFyaWFibGVzDQoNCmBgYHtyfQ0KcmVzZEhpQW5ub3lGaXQgPC0gZGF0YS5mcmFtZShSTVNFID0gbnVtZXJpYygpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBNQUUgPSBudW1lcmljKCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIFJzcXVhcmVkID0gbnVtZXJpYygpKQ0KcmVzZEhpQW5ub3lQZXJtSW1wIDwtIGxpc3QoKQ0KDQpgYGANCg0KIyMjIEFsbCB2YXJpYWJsZXMgKGFic29sdXRlIGFuZCBkaWZmZXJlbmNlKQ0KDQojIyMjIFJlbW92ZSBhbWJpZW50IG9ubHkgc3RpbXVsaQ0KDQpIZXJlLCB0aGUgJ2FtYmllbnQgb25seScgc3RpbXVsaSBhcmUgcmVtb3ZlZCwgYXMgdGhlIGFuYWx5c2lzIGNhbm5vdCBoYW5kbGUgbWlzc2luZyB2YWx1ZXMgZm9yIGRCIG1ldHJpY3MuDQoNCmBgYHtyfQ0Kc3RpbURhdGFBTnVtIDwtIHN0aW1EYXRhQU51bVtjb21wbGV0ZS5jYXNlcyhzdGltRGF0YUFOdW0pLF0NCnN0aW1EYXRhQU51bSRVQVNMQWVxIDwtIGFzLm51bWVyaWMoc3RpbURhdGFBTnVtJFVBU0xBZXEpDQpzdGltRGF0YUFOdW0kU05SbGV2ZWwgPC0gYXMubnVtZXJpYyhzdGltRGF0YUFOdW0kU05SbGV2ZWwpDQpgYGANCg0KIyMjIyBTZXQgdmFyaWFibGVzDQoNCmBgYHtyfQ0KDQppVmFycyA8LSBuYW1lcyhzdGltRGF0YUFOdW0pW3doaWNoKG5hbWVzKHN0aW1EYXRhQU51bSkgPT0gJ1VBU0xBZXEnKTp3aGljaChuYW1lcyhzdGltRGF0YUFOdW0pID09ICdVQVNJbXB1bHNTSE0wNUV4TWF4TFInKV0NCmlWYXJzIDwtIGlWYXJzWyEgaVZhcnMgJWluJSAnU05SbGV2ZWwnXQ0KaVZhcnMgPC0gYyhpVmFycywNCiAgICAgICAgICAgbmFtZXMoc3RpbURhdGFBTnVtKVt3aGljaChjb2xuYW1lcyhzdGltRGF0YUFOdW0pPT0iTEFlcUxBRjkwZGlmZiIpOg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoKGNvbG5hbWVzKHN0aW1EYXRhQU51bSk9PSJkSW1wdWxzU0hNMDVFeE1heExSIildLCAiU05SbGV2ZWwiKQ0KZFZhciA8LSAiZEhpZ2hBbm5veVBjIg0KDQpzZWVkcyA8LSBjKDIsIDMxMiwgMTg5NywgNDY1OTc4LCA4MjE2NTkpDQoNCmBgYA0KDQojIyMjIEh5cGVycGFyYW1ldGVyIHR1bmluZw0KDQpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTR9DQoNCnAgPC0gbXRyeVR1bmUoZGF0YUluPXN0aW1EYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZD1zZWVkc1sxXSwNCiAgICAgICAgICAgICAgbnRyZWVzPW50cmVlcywgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQpwDQoNCmBgYA0KDQpTZWxlY3RlZCBoeXBlcnBhcmFtZXRlcnMNCg0KYGBge3J9DQoNCm50cmVlIDwtIDUwMQ0KbXRyeSA8LSBhcy5pbnRlZ2VyKGxlbmd0aChpVmFycykvMS43NSkNCg0KYGBgDQoNCiMjIyMgUnVuIG1vZGVsDQoNClRyYWluIHByZWxpbWluYXJ5IG1vZGVsDQoNCmBgYHtyfQ0KDQpucGVybSA8LSA1DQoNCnJlc3VsdHNPdXRBYnNEaWZmcyA8LSBjcmZSZWcoZGF0YUluPXN0aW1EYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHNbMToyXSwgbnRyZWU9bnRyZWUsIG10cnk9bXRyeSwgcGVybUltcENvbmRUaHJlcz1wZXJtSW1wQ29uZFRocmVzLCBucGVybT1ucGVybSwgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQoNCiMgcHJpbnQgbW9kZWwgcHJlZGljdGlvbiByZXN1bHRzDQpyZXN1bHRzT3V0QWJzRGlmZnMkT09CX1JNU0UNCnJlc3VsdHNPdXRBYnNEaWZmcyRPT0JfTUFFDQpyZXN1bHRzT3V0QWJzRGlmZnMkUnNxdWFyZWQNCg0KYGBgDQoNClRyYWluIG11bHRpcGxlIHNlZWRzIG1vZGVsDQoNCmBgYHtyfQ0KDQpyZXN1bHRzT3V0QWJzRGlmZnMgPC0gbXVsdGlfY3JmUmVnKGRhdGFJbj1zdGltRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzLCBudHJlZT1udHJlZSwgbXRyeT1tdHJ5LCBwZXJtSW1wQ29uZFRocmVzPXBlcm1JbXBDb25kVGhyZXMsIG5wZXJtPW5wZXJtLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCg0KIyBwcmludCBtb2RlbCBwcmVkaWN0aW9uIHJlc3VsdHMNCnJlc3VsdHNPdXRBYnNEaWZmcyRPT0JfUk1TRQ0KcmVzdWx0c091dEFic0RpZmZzJE9PQl9NQUUNCnJlc3VsdHNPdXRBYnNEaWZmcyRSc3F1YXJlZA0KYGBgDQoNCmBgYHtyfQ0KIyBzdG9yZSByZXN1bHRzDQpyZXNkSGlBbm5veUZpdFsnQWxsIHZhcnMnLCAnUk1TRSddIDwtIHJlc3VsdHNPdXRBYnNEaWZmcyRPT0JfUk1TRQ0KcmVzZEhpQW5ub3lGaXRbJ0FsbCB2YXJzJywgJ01BRSddIDwtIHJlc3VsdHNPdXRBYnNEaWZmcyRPT0JfTUFFDQpyZXNkSGlBbm5veUZpdFsnQWxsIHZhcnMnLCAnUnNxdWFyZWQnXSA8LSByZXN1bHRzT3V0QWJzRGlmZnMkUnNxdWFyZWQNCnJlc2RIaUFubm95UGVybUltcCRBbGxWYXJzIDwtIHJlc3VsdHNPdXRBYnNEaWZmcyRjb25kaXRpb25hbF9wZXJtaW1wDQoNCmBgYA0KDQojIyMjIFBsb3QgcmVzdWx0cw0KDQpgYGB7ciwgZmlnLndpZHRoPTgsZmlnLmhlaWdodD0yMH0NCnBhcihtYWk9YygwLDMsMCwwKSkNCg0KIyBwbG90IGNvbmRpdGlvbmFsIGltcG9ydGFuY2UNCnJlc3VsdHNPdXRBYnNEaWZmcy5jb25pbXAgPC0gYXJyYW5nZShyZXN1bHRzT3V0QWJzRGlmZnMkY29uZGl0aW9uYWxfcGVybWltcCwgZGVzYyhyb3dfbnVtYmVyKCkpKQ0KDQpwQmFyIDwtIGdncGxvdChyZXN1bHRzT3V0QWJzRGlmZnMuY29uaW1wKSArIGdlb21fY29sKGFlcyh4PWZhY3Rvcihyb3duYW1lcyhyZXN1bHRzT3V0QWJzRGlmZnMuY29uaW1wKSwgbGV2ZWxzPXJvd25hbWVzKHJlc3VsdHNPdXRBYnNEaWZmcy5jb25pbXApKSwgeT1Db25kUGVybUltcCksIGZpbGw9bXljb2xvdXJzWzldLCB3aWR0aD0wLjUpICsgbGFicyh4PSJWYXJpYWJsZSIsIHk9IkNvbmRpdGlvbmFsIHZhcmlhYmxlIHBlcm11dGF0aW9uIGltcG9ydGFuY2UgKCUgaGlnaGx5IGFubm95ZWQpIikgKyB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIpLCBwYW5lbC5ncmlkPWVsZW1lbnRfbGluZShjb2xvciA9IHJnYigyMzUsIDIzNSwgMjM1LCAxMDAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCBsaW5ld2lkdGggPSAwLjI1LCBsaW5ldHlwZSA9IDIpKSArIGNvb3JkX2ZsaXAoKQ0KcEJhcg0KDQppZiAoc2F2ZXBsb3RzKXsNCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFkSGlBbm5veUFsbFZhcnNDb25QZXJtaW1wLnN2ZyIsIHdpZHRoPTgsIGhlaWdodD0yMCwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInN2ZyIpKQ0KICB1bmxpbmsoIlB0QWRIaUFubm95QWxsVmFyc0NvblBlcm1pbXAuc3ZnIikNCg0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWRIaUFubm95QWxsVmFyc0NvblBlcm1pbXAucGRmIiwgd2lkdGg9OCwgaGVpZ2h0PTIwLCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAicGRmIikpDQogIHVubGluaygiUHRBZEhpQW5ub3lBbGxWYXJzQ29uUGVybWltcC5wZGYiKQ0KfQ0KDQpgYGANCg0KYGBge3IsIGZpZy53aWR0aD04LGZpZy5oZWlnaHQ9MTJ9DQoNCiMgUGxvdCBvbmx5IHBvc2l0aXZlIHZhbHVlcw0KDQpyZXN1bHRzT3V0QWJzRGlmZnMuY29uaW1wUHR2IDwtIHJlc3VsdHNPdXRBYnNEaWZmcy5jb25pbXAgfD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvd25hbWVzX3RvX2NvbHVtbignTWV0cmljJykgfD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcl9pZihpcy5udW1lcmljLCBhbGxfdmFycyguID4gMCkpIHw+DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2x1bW5fdG9fcm93bmFtZXMoJ01ldHJpYycpDQoNCnBCYXIgPC0gZ2dwbG90KHJlc3VsdHNPdXRBYnNEaWZmcy5jb25pbXBQdHYpICsgZ2VvbV9jb2woYWVzKHg9ZmFjdG9yKHJvd25hbWVzKHJlc3VsdHNPdXRBYnNEaWZmcy5jb25pbXBQdHYpLCBsZXZlbHM9cm93bmFtZXMocmVzdWx0c091dEFic0RpZmZzLmNvbmltcFB0dikpLCB5PUNvbmRQZXJtSW1wKSwgZmlsbD1teWNvbG91cnNbOV0sIHdpZHRoPTAuNSkgKyBsYWJzKHg9IlZhcmlhYmxlIiwgeT0iQ29uZGl0aW9uYWwgdmFyaWFibGUgcGVybXV0YXRpb24gaW1wb3J0YW5jZSAoJSBoaWdobHkgYW5ub3llZCkiKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiksIHBhbmVsLmdyaWQ9ZWxlbWVudF9saW5lKGNvbG9yID0gcmdiKDIzNSwgMjM1LCAyMzUsIDEwMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksIGxpbmV3aWR0aCA9IDAuMjUsIGxpbmV0eXBlID0gMikpICsgY29vcmRfZmxpcCgpDQpwQmFyDQoNCmlmIChzYXZlcGxvdHMpew0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWRIaUFubm95QWxsVmFyc0NvblBlcm1pbXBQdHYuc3ZnIiwgd2lkdGg9OCwgaGVpZ2h0PTEyLCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAic3ZnIikpDQogIHVubGluaygiUHRBZEhpQW5ub3lBbGxWYXJzQ29uUGVybWltcC5zdmciKQ0KICANCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFkSGlBbm5veUFsbFZhcnNDb25QZXJtaW1wUHR2LnBkZiIsIHdpZHRoPTgsIGhlaWdodD0xMiwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInBkZiIpKQ0KICB1bmxpbmsoIlB0QWRIaUFubm95QWxsVmFyc0NvblBlcm1pbXAucGRmIikNCn0NCg0KYGBgDQoNCiMjIyBBYnNvbHV0ZSB2YXJpYWJsZXMNCg0KIyMjIyBTZXQgdmFyaWFibGVzDQoNCmBgYHtyfQ0KDQppVmFycyA8LSBuYW1lcyhzdGltRGF0YUFOdW0pW3doaWNoKG5hbWVzKHN0aW1EYXRhQU51bSkgPT0gJ1VBU0xBZXEnKTp3aGljaChuYW1lcyhzdGltRGF0YUFOdW0pID09ICdVQVNJbXB1bHNTSE0wNUV4TWF4TFInKV0NCmlWYXJzIDwtIGlWYXJzWyEgaVZhcnMgJWluJSBjKCdTTlJsZXZlbCcpXQ0KZFZhciA8LSAiZEhpZ2hBbm5veVBjIg0KDQpzZWVkcyA8LSBjKDU3ODMxMiwgNTQ0LCA4NDg5NCwgNTQ2NTQsIDE1MzE1NykNCg0KYGBgDQoNCiMjIyMgSHlwZXJwYXJhbWV0ZXIgdHVuaW5nDQoNCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NH0NCg0KcCA8LSBtdHJ5VHVuZShkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkPXNlZWRzWzFdLA0KICAgICAgICAgICAgIG50cmVlcz1udHJlZXMsIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KcA0KDQppZiAoc2F2ZXBsb3RzKXsNCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFkSGlBbm5veUFic1ZhcnNIeXBlclR1bmUuc3ZnIiwgd2lkdGg9MTIsIGhlaWdodD00LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAic3ZnIikpDQogIHVubGluaygiUHRBZEhpQW5ub3lBYnNWYXJzSHlwZXJUdW5lLnN2ZyIpDQoNCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFkSGlBbm5veUFic1ZhcnNIeXBlclR1bmUucGRmIiwgd2lkdGg9MTIsIGhlaWdodD00LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAicGRmIikpDQogIHVubGluaygiUHRBZEhpQW5ub3lBYnNWYXJzSHlwZXJUdW5lLnBkZiIpDQp9DQoNCmBgYA0KDQpTZWxlY3RlZCBoeXBlcnBhcmFtZXRlcnMNCg0KYGBge3J9DQoNCm50cmVlIDwtIDUwMQ0KbXRyeSA8LSBhcy5pbnRlZ2VyKGxlbmd0aChpVmFycykvMS4yNSkNCg0KYGBgDQoNCiMjIyMgUnVuIG1vZGVsDQoNClRyYWluIHByZWxpbWluYXJ5IG1vZGVsDQoNCmBgYHtyfQ0KDQpucGVybSA8LSAyMA0KDQpyZXN1bHRzT3V0QWJzIDwtIGNyZlJlZyhkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkc1sxOjJdLCBudHJlZT1udHJlZSwgbXRyeT1tdHJ5LCBwZXJtSW1wQ29uZFRocmVzPXBlcm1JbXBDb25kVGhyZXMsIG5wZXJtPW5wZXJtLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCg0KIyBwcmludCBtb2RlbCBwcmVkaWN0aW9uIHJlc3VsdHMNCnJlc3VsdHNPdXRBYnMkT09CX1JNU0UNCnJlc3VsdHNPdXRBYnMkT09CX01BRQ0KcmVzdWx0c091dEFicyRSc3F1YXJlZA0KDQpgYGANClRyYWluIG11bHRpcGxlIHNlZWRzIG1vZGVsDQoNCmBgYHtyfQ0KDQpyZXN1bHRzT3V0QWJzIDwtIG11bHRpX2NyZlJlZyhkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkcywgbnRyZWU9bnRyZWUsIG10cnk9bXRyeSwgcGVybUltcENvbmRUaHJlcz1wZXJtSW1wQ29uZFRocmVzLCBucGVybT1ucGVybSwgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQoNCiMgcHJpbnQgbW9kZWwgcHJlZGljdGlvbiByZXN1bHRzDQpyZXN1bHRzT3V0QWJzJE9PQl9STVNFDQpyZXN1bHRzT3V0QWJzJE9PQl9NQUUNCnJlc3VsdHNPdXRBYnMkUnNxdWFyZWQNCg0KYGBgDQoNCg0KYGBge3J9DQoNCiMgc3RvcmUgcmVzdWx0cw0KcmVzZEhpQW5ub3lGaXRbJ0FicyB2YXJzJywgJ1JNU0UnXSA8LSByZXN1bHRzT3V0QWJzJE9PQl9STVNFDQpyZXNkSGlBbm5veUZpdFsnQWJzIHZhcnMnLCAnTUFFJ10gPC0gcmVzdWx0c091dEFicyRPT0JfTUFFDQpyZXNkSGlBbm5veUZpdFsnQWJzIHZhcnMnLCAnUnNxdWFyZWQnXSA8LSByZXN1bHRzT3V0QWJzJFJzcXVhcmVkDQpyZXNkSGlBbm5veVBlcm1JbXAkQWJzVmFycyA8LSByZXN1bHRzT3V0QWJzJGNvbmRpdGlvbmFsX3Blcm1pbXANCg0KYGBgDQoNCiMjIyMgUGxvdCByZXN1bHRzDQoNCmBgYHtyLCBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTExLjV9DQpwYXIobWFpPWMoMCwzLDAsMCkpDQoNCiMgcGxvdCBjb25kaXRpb25hbCBpbXBvcnRhbmNlDQpyZXN1bHRzT3V0QWJzLmNvbmltcCA8LSBhcnJhbmdlKHJlc3VsdHNPdXRBYnMkY29uZGl0aW9uYWxfcGVybWltcCwgZGVzYyhyb3dfbnVtYmVyKCkpKQ0KDQpwQmFyIDwtIGdncGxvdChyZXN1bHRzT3V0QWJzLmNvbmltcCkgKyBnZW9tX2NvbChhZXMoeD1mYWN0b3Iocm93bmFtZXMocmVzdWx0c091dEFicy5jb25pbXApLCBsZXZlbHM9cm93bmFtZXMocmVzdWx0c091dEFicy5jb25pbXApKSwgeT1Db25kUGVybUltcCksIGZpbGw9bXljb2xvdXJzWzFdLCB3aWR0aD0wLjUpICsgbGFicyh4PSJWYXJpYWJsZSIsIHk9IkNvbmRpdGlvbmFsIHZhcmlhYmxlIHBlcm11dGF0aW9uIGltcG9ydGFuY2UgKCUgaGlnaGx5IGFubm95ZWQpIikgKyB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIpLCBwYW5lbC5ncmlkPWVsZW1lbnRfbGluZShjb2xvciA9IHJnYigyMzUsIDIzNSwgMjM1LCAxMDAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCBsaW5ld2lkdGggPSAwLjI1LCBsaW5ldHlwZSA9IDIpKSArDQogIGNvb3JkX2ZsaXAoKQ0KcEJhcg0KDQppZiAoc2F2ZXBsb3RzKXsNCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFkSGlBbm5veUFic1ZhcnNDb25QZXJtaW1wLnN2ZyIsIHdpZHRoPTgsIGhlaWdodD0xMS41LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAic3ZnIikpDQogIHVubGluaygiUHRBZEhpQW5ub3lBYnNWYXJzQ29uUGVybWltcC5zdmciKQ0KICANCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFkSGlBbm5veUFic1ZhcnNDb25QZXJtaW1wLnBkZiIsIHdpZHRoPTgsIGhlaWdodD0xMS41LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAicGRmIikpDQogIHVubGluaygiUHRBZEhpQW5ub3lBYnNWYXJzQ29uUGVybWltcC5wZGYiKQ0KfQ0KYGBgDQoNCmBgYHtyLCBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTd9DQoNCiMgUGxvdCBvbmx5IHBvc2l0aXZlIHZhbHVlcw0KcmVzdWx0c091dEFicy5jb25pbXBQdHYgPC0gcmVzdWx0c091dEFicy5jb25pbXAgfD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvd25hbWVzX3RvX2NvbHVtbignTWV0cmljJykgfD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcl9pZihpcy5udW1lcmljLCBhbGxfdmFycyguID4gMCkpIHw+DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2x1bW5fdG9fcm93bmFtZXMoJ01ldHJpYycpDQoNCnBCYXIgPC0gZ2dwbG90KHJlc3VsdHNPdXRBYnMuY29uaW1wUHR2LCkgKyBnZW9tX2NvbChhZXMoeD1mYWN0b3Iocm93bmFtZXMocmVzdWx0c091dEFicy5jb25pbXBQdHYpLCBsZXZlbHM9cm93bmFtZXMocmVzdWx0c091dEFicy5jb25pbXBQdHYpKSwgeT1Db25kUGVybUltcCksIGZpbGw9bXljb2xvdXJzWzFdLCB3aWR0aD0wLjUpICsgbGFicyh4PSJWYXJpYWJsZSIsIHk9IkNvbmRpdGlvbmFsIHZhcmlhYmxlIHBlcm11dGF0aW9uIGltcG9ydGFuY2UgKCUgaGlnaGx5IGFubm95ZWQpIikgKyB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIpLCBwYW5lbC5ncmlkPWVsZW1lbnRfbGluZShjb2xvciA9IHJnYigyMzUsIDIzNSwgMjM1LCAxMDAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCBsaW5ld2lkdGggPSAwLjI1LCBsaW5ldHlwZSA9IDIpKSArIGNvb3JkX2ZsaXAoKQ0KcEJhcg0KDQppZiAoc2F2ZXBsb3RzKXsNCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFkSGlBbm5veUFic1ZhcnNDb25QZXJtaW1wUHR2LnN2ZyIsIHdpZHRoPTgsIGhlaWdodD03LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAic3ZnIikpDQogIHVubGluaygiUHRBZEhpQW5ub3lBYnNWYXJzQ29uUGVybWltcFB0di5zdmciKQ0KICANCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFkSGlBbm5veUFic1ZhcnNDb25QZXJtaW1wUHR2LnBkZiIsIHdpZHRoPTgsIGhlaWdodD03LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAicGRmIikpDQogIHVubGluaygiUHRBZEhpQW5ub3lBYnNWYXJzQ29uUGVybWltcFB0di5wZGYiKQ0KfQ0KDQpgYGANCg0KU2VsZWN0ZWQgbWV0cmljDQoNCmBgYHtyfQ0KDQphYnNWYXIgPC0gIlVBU0xvdWRJU08zUG93QXZnQmluIg0KDQpgYGANCg0KIyMjIFNRTSBhbmFseXNpcw0KDQojIyMjIFJlcGxhY2UgYW1iaWVudCBvbmx5IHN0aW11bGkNCg0KSGVyZSwgdGhlICdhbWJpZW50IG9ubHknIHN0aW11bGkgYXJlIHJlcGxhY2VkLCBhcyB0aGUgU1FNIGFuYWx5c2lzIGNhbiBpbmNvcnBvcmF0ZSAwIHZhbHVlcyAod2hlcmVhcyBkQiBtZXRyaWNzIGNhbm5vdCBiZSBoYW5kbGVkIGluIHRoaXMgd2F5KS4NCg0KYGBge3J9DQoNCnN0aW1EYXRhQU51bSA8LSByYmluZChzdGltRGF0YUFOdW0sIHN0aW1EYXRhQVtzdGltRGF0YUFbJ1N0aW11bHVzJ10NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA9PSAiQTEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG5hbWVzKHN0aW1EYXRhQU51bSldLA0KICAgICAgICAgICAgICAgICAgICAgIHN0aW1EYXRhQVtzdGltRGF0YUFbJ1N0aW11bHVzJ10NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA9PSAiQTIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG5hbWVzKHN0aW1EYXRhQU51bSldKQ0Kc3RpbURhdGFBTnVtIDwtIGFycmFuZ2Uoc3RpbURhdGFBTnVtLCBTdGltdWx1cykNCg0KYGBgDQoNCiMjIyMgSW5kaXZpZHVhbCBTUU1zDQoNCiMjIyMjIFNoYXJwbmVzcw0KDQojIyMjIyMgU2V0IHZhcmlhYmxlcw0KDQpgYGB7cn0NCg0KaVZhcnMgPC0gYyhhYnNWYXIsICJBbWJpZW50TEFlcSIsICJVQVNTaGFycEF1cklTTzNQb3dBdmdNYXhMUiIsICJVQVNTaGFycEF1cklTTzMwNUV4TWF4TFIiLCAiVUFTU2hhcnBBdXJTSE1Qb3dBdmdNYXhMUiIsICJVQVNTaGFycEF1clNITTA1RXhNYXhMUiIsICJVQVNTaGFycEF1cklTTzFQb3dBdmdNYXhMUiIsICJVQVNTaGFycEF1cklTTzEwNUV4TWF4TFIiLCAiVUFTU2hhcnB2QklTTzFQb3dBdmdNYXhMUiIsICJVQVNTaGFycHZCSVNPMTA1RXhNYXhMUiIsICJVQVNTaGFycERJTlBvd0F2Z01heExSIiwgIlVBU1NoYXJwRElOMDVFeE1heExSIikNCmRWYXIgPC0gImRIaWdoQW5ub3lQYyINCg0Kc2VlZHMgPC0gYyg3MDQxLCA5MDUsIDQ5ODQ2NTEsIDY1MTMyMTMsIDEyMDY1MSkNCg0KYGBgDQoNCiMjIyMjIyBIeXBlcnBhcmFtZXRlciB0dW5pbmcNCg0KYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD00fQ0KDQpwIDwtIG10cnlUdW5lKGRhdGFJbj1zdGltRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWQ9c2VlZHNbMV0sDQogICAgICAgICAgICAgbnRyZWVzPW50cmVlcywgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQpwDQoNCmBgYA0KDQpTZWxlY3RlZCBoeXBlcnBhcmFtZXRlcnMNCg0KYGBge3J9DQoNCm50cmVlIDwtIDI1MQ0KbXRyeSA8LSBhcy5pbnRlZ2VyKGxlbmd0aChpVmFycykvMi43NSkNCg0KYGBgDQoNCiMjIyMjIyBSdW4gbW9kZWwNCg0KVHJhaW4gcHJlbGltaW5hcnkgbW9kZWwNCg0KYGBge3J9DQoNCm5wZXJtIDwtIDUNCg0KcmVzdWx0c091dFNoYXJwIDwtIGNyZlJlZyhkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkc1sxOjJdLCBudHJlZT1udHJlZSwgbXRyeT1tdHJ5LCBwZXJtSW1wQ29uZFRocmVzPXBlcm1JbXBDb25kVGhyZXMsIG5wZXJtPW5wZXJtLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCg0KIyBwcmludCBtb2RlbCBwcmVkaWN0aW9uIHJlc3VsdHMNCnJlc3VsdHNPdXRTaGFycCRPT0JfUk1TRQ0KcmVzdWx0c091dFNoYXJwJE9PQl9NQUUNCnJlc3VsdHNPdXRTaGFycCRSc3F1YXJlZA0KDQpgYGANClRyYWluIG11bHRpcGxlIHNlZWRzIG1vZGVsDQoNCmBgYHtyfQ0KDQpyZXN1bHRzT3V0U2hhcnAgPC0gbXVsdGlfY3JmUmVnKGRhdGFJbj1zdGltRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzLCBudHJlZT1udHJlZSwgbXRyeT1tdHJ5LCBwZXJtSW1wQ29uZFRocmVzPXBlcm1JbXBDb25kVGhyZXMsIG5wZXJtPW5wZXJtLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCg0KIyBwcmludCBtb2RlbCBwcmVkaWN0aW9uIHJlc3VsdHMNCnJlc3VsdHNPdXRTaGFycCRPT0JfUk1TRQ0KcmVzdWx0c091dFNoYXJwJE9PQl9NQUUNCnJlc3VsdHNPdXRTaGFycCRSc3F1YXJlZA0KDQpgYGANCg0KDQpgYGB7cn0NCiMgc3RvcmUgcmVzdWx0cw0KcmVzZEhpQW5ub3lGaXRbJ0FicyBzaGFycCcsICdSTVNFJ10gPC0gcmVzdWx0c091dFNoYXJwJE9PQl9STVNFDQpyZXNkSGlBbm5veUZpdFsnQWJzIHNoYXJwJywgJ01BRSddIDwtIHJlc3VsdHNPdXRTaGFycCRPT0JfTUFFDQpyZXNkSGlBbm5veUZpdFsnQWJzIHNoYXJwJywgJ1JzcXVhcmVkJ10gPC0gcmVzdWx0c091dFNoYXJwJFJzcXVhcmVkDQpyZXNkSGlBbm5veVBlcm1JbXAkQWJzU2hhcnAgPC0gcmVzdWx0c091dFNoYXJwJGNvbmRpdGlvbmFsX3Blcm1pbXANCg0KYGBgDQoNCiMjIyMjIyBQbG90IHJlc3VsdHMNCg0KYGBge3IsIGZpZy53aWR0aD04LGZpZy5oZWlnaHQ9NC45fQ0KcGFyKG1haT1jKDAsMywwLDApKQ0KDQojIHBsb3QgY29uZGl0aW9uYWwgaW1wb3J0YW5jZQ0KcmVzdWx0c091dFNoYXJwLmNvbmltcCA8LSBhcnJhbmdlKHJlc3VsdHNPdXRTaGFycCRjb25kaXRpb25hbF9wZXJtaW1wLCBkZXNjKHJvd19udW1iZXIoKSkpDQoNCnBCYXIgPC0gZ2dwbG90KHJlc3VsdHNPdXRTaGFycC5jb25pbXApICsgZ2VvbV9jb2woYWVzKHg9ZmFjdG9yKHJvd25hbWVzKHJlc3VsdHNPdXRTaGFycC5jb25pbXApLCBsZXZlbHM9cm93bmFtZXMocmVzdWx0c091dFNoYXJwLmNvbmltcCkpLCB5PUNvbmRQZXJtSW1wKSwgZmlsbD1teWNvbG91cnNbMl0sIHdpZHRoPTAuNSkgKyBsYWJzKHg9IlZhcmlhYmxlIiwgeT0iQ29uZGl0aW9uYWwgdmFyaWFibGUgcGVybXV0YXRpb24gaW1wb3J0YW5jZSAoJSBoaWdobHkgYW5ub3llZCkiKSArIGdndGl0bGUoIlNoYXJwbmVzcyIpICsgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2VyaWYiKSwgcGFuZWwuZ3JpZD1lbGVtZW50X2xpbmUoY29sb3IgPSByZ2IoMjM1LCAyMzUsIDIzNSwgMTAwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgbGluZXdpZHRoID0gMC4yNSwgbGluZXR5cGUgPSAyKSkgKyBjb29yZF9mbGlwKCkNCnBCYXINCg0KaWYgKHNhdmVwbG90cyl7DQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBZEhpQW5ub3lTaGFycENvblBlcm1pbXAuc3ZnIiwgd2lkdGg9OCwgaGVpZ2h0PTQuOSwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInN2ZyIpKQ0KICB1bmxpbmsoIlB0QWRIaUFubm95U2hhcnBDb25QZXJtaW1wLnN2ZyIpDQogIA0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWRIaUFubm95U2hhcnBDb25QZXJtaW1wLnBkZiIsIHdpZHRoPTgsIGhlaWdodD00LjksIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJwZGYiKSkNCiAgdW5saW5rKCJQdEFkSGlBbm5veVNoYXJwQ29uUGVybWltcC5wZGYiKQ0KfQ0KDQoNCmBgYA0KDQpTZWxlY3RlZCBtZXRyaWMNCg0KYGBge3J9DQoNCnNoYXJwVmFyIDwtICJVQVNTaGFycEF1cklTTzMwNUV4TWF4TFIiDQoNCmBgYA0KDQoNCiMjIyMjIFRvbmFsIGxvdWRuZXNzIGFuZCB0b25hbGl0eQ0KDQojIyMjIyMgU2V0IHZhcmlhYmxlcw0KDQpgYGB7cn0NCg0KaVZhcnMgPC0gYyhhYnNWYXIsICJBbWJpZW50TEFlcSIsICJVQVNUb25hbEVDTUFBdmdNYXhMUiIsICJVQVNUb25hbFNITUludDA1RXhNYXhMUiIsICJVQVNUb25hbFNITUludEF2Z01heExSIiwgIlVBU1RvbmFsRUNNQTA1RXhNYXhMUiIsICJVQVNUb25MZEVDTUFQb3dBdmdCaW4iLCAiVUFTVG9uTGRFQ01BMDVFeEJpbiIsICJVQVNUb25hbEF1ckF2Z01heExSIiwgIlVBU1RvbmFsQXVyMDVFeE1heExSIiwgIlVBU1RvbmFsQXVyMTBFeE1heExSIikNCmRWYXIgPC0gImRIaWdoQW5ub3lQYyINCg0Kc2VlZHMgPC0gYyg1NDAsIDEwNDc5OCwgNDU2NDY0LCA4NzMzMSwgOTQ1NjQpDQoNCmBgYA0KDQojIyMjIyMgSHlwZXJwYXJhbWV0ZXIgdHVuaW5nDQoNCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NH0NCg0KcCA8LSBtdHJ5VHVuZShkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkPXNlZWRzWzFdLA0KICAgICAgICAgICAgIG50cmVlcz1udHJlZXMsIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KcA0KDQpgYGANCg0KU2VsZWN0ZWQgaHlwZXJwYXJhbWV0ZXJzDQoNCmBgYHtyfQ0KDQpudHJlZSA8LSAyNTENCm10cnkgPC0gYXMuaW50ZWdlcihsZW5ndGgoaVZhcnMpLzEuNSkNCg0KYGBgDQoNCiMjIyMjIyBSdW4gbW9kZWwNCg0KVHJhaW4gcHJlbGltaW5hcnkgbW9kZWwNCg0KYGBge3J9DQojIFRvbmFsaXR5IHdpdGggdG9uYWwgbG91ZG5lc3MNCg0KbnBlcm0gPC0gNQ0KDQpyZXN1bHRzT3V0VG9uYWwxIDwtIGNyZlJlZyhkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkc1sxOjJdLCBudHJlZT1udHJlZSwgbXRyeT1tdHJ5LCBwZXJtSW1wQ29uZFRocmVzPXBlcm1JbXBDb25kVGhyZXMsIG5wZXJtPW5wZXJtLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCg0KIyBwcmludCBtb2RlbCBwcmVkaWN0aW9uIHJlc3VsdHMNCnJlc3VsdHNPdXRUb25hbDEkT09CX1JNU0UNCnJlc3VsdHNPdXRUb25hbDEkT09CX01BRQ0KcmVzdWx0c091dFRvbmFsMSRSc3F1YXJlZA0KYGBgDQoNClRyYWluIG11bHRpcGxlIHNlZWRzIG1vZGVsDQoNCmBgYHtyfQ0KIyBUb25hbGl0eSB3aXRoIHRvbmFsIGxvdWRuZXNzDQoNCnJlc3VsdHNPdXRUb25hbDEgPC0gbXVsdGlfY3JmUmVnKGRhdGFJbj1zdGltRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzLCBudHJlZT1udHJlZSwgbXRyeT1tdHJ5LCBwZXJtSW1wQ29uZFRocmVzPXBlcm1JbXBDb25kVGhyZXMsIG5wZXJtPW5wZXJtLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCg0KIyBwcmludCBtb2RlbCBwcmVkaWN0aW9uIHJlc3VsdHMNCnJlc3VsdHNPdXRUb25hbDEkT09CX1JNU0UNCnJlc3VsdHNPdXRUb25hbDEkT09CX01BRQ0KcmVzdWx0c091dFRvbmFsMSRSc3F1YXJlZA0KDQpgYGANCg0KYGBge3J9DQojIHN0b3JlIHJlc3VsdHMNCnJlc2RIaUFubm95Rml0WydBYnMgdG9uYWwgaW5jIGxvdWQnLCAnUk1TRSddIDwtIHJlc3VsdHNPdXRUb25hbDEkT09CX1JNU0UNCnJlc2RIaUFubm95Rml0WydBYnMgdG9uYWwgaW5jIGxvdWQnLCAnTUFFJ10gPC0gcmVzdWx0c091dFRvbmFsMSRPT0JfTUFFDQpyZXNkSGlBbm5veUZpdFsnQWJzIHRvbmFsIGluYyBsb3VkJywgJ1JzcXVhcmVkJ10gPC0gcmVzdWx0c091dFRvbmFsMSRSc3F1YXJlZA0KcmVzZEhpQW5ub3lQZXJtSW1wJEFic1RvbmFsMSA8LSByZXN1bHRzT3V0VG9uYWwxJGNvbmRpdGlvbmFsX3Blcm1pbXANCg0KYGBgDQoNCiMjIyMjIyBQbG90IHJlc3VsdHMNCg0KYGBge3IsIGZpZy53aWR0aD04LGZpZy5oZWlnaHQ9My44fQ0KDQpwYXIobWFpPWMoMCwzLDAsMCkpDQoNCiMgcGxvdCBjb25kaXRpb25hbCBpbXBvcnRhbmNlDQpyZXN1bHRzT3V0VG9uYWwxLmNvbmltcCA8LSBhcnJhbmdlKHJlc3VsdHNPdXRUb25hbDEkY29uZGl0aW9uYWxfcGVybWltcCwgZGVzYyhyb3dfbnVtYmVyKCkpKQ0KDQpwQmFyIDwtIGdncGxvdChyZXN1bHRzT3V0VG9uYWwxLmNvbmltcCkgKyBnZW9tX2NvbChhZXMoeD1mYWN0b3Iocm93bmFtZXMocmVzdWx0c091dFRvbmFsMS5jb25pbXApLCBsZXZlbHM9cm93bmFtZXMocmVzdWx0c091dFRvbmFsMS5jb25pbXApKSwgeT1Db25kUGVybUltcCksIGZpbGw9bXljb2xvdXJzWzNdLCB3aWR0aD0wLjUpICsgbGFicyh4PSJWYXJpYWJsZSIsIHk9IkNvbmRpdGlvbmFsIHZhcmlhYmxlIHBlcm11dGF0aW9uIGltcG9ydGFuY2UgKCUgaGlnaGx5IGFubm95ZWQpIikgKyBnZ3RpdGxlKCJUb25hbGl0eSBpbmMuIHRvbmFsIGxvdWRuZXNzIikgKyB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIpLCBwYW5lbC5ncmlkPWVsZW1lbnRfbGluZShjb2xvciA9IHJnYigyMzUsIDIzNSwgMjM1LCAxMDAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCBsaW5ld2lkdGggPSAwLjI1LCBsaW5ldHlwZSA9IDIpKSArIGNvb3JkX2ZsaXAoeWxpbT1jKC0xLCA3MCkpDQpwQmFyDQoNCmlmIChzYXZlcGxvdHMpew0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWRIaUFubm95VG9uYWxMZENvblBlcm1pbXAuc3ZnIiwgd2lkdGg9OCwgaGVpZ2h0PTMuOCwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInN2ZyIpKQ0KICB1bmxpbmsoIlB0QWRIaUFubm95VG9uYWxMZENvblBlcm1pbXAuc3ZnIikNCiAgDQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBZEhpQW5ub3lUb25hbExkQ29uUGVybWltcC5wZGYiLCB3aWR0aD04LCBoZWlnaHQ9My44LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAicGRmIikpDQogIHVubGluaygiUHRBZEhpQW5ub3lUb25hbExkQ29uUGVybWltcC5wZGYiKQ0KfQ0KDQpgYGANCg0KU2VsZWN0ZWQgbWV0cmljDQoNCmBgYHtyfQ0KDQp0b25MZFZhciA8LSAiVUFTVG9uTGRFQ01BUG93QXZnQmluIg0KDQpgYGANCg0KDQojIyMjIyBUb25hbGl0eSB3aXRob3V0IHRvbmFsIGxvdWRuZXNzDQoNCiMjIyMjIyBTZXQgdmFyaWFibGVzDQoNCmBgYHtyfQ0KDQppVmFycyA8LSBjKGFic1ZhciwgIkFtYmllbnRMQWVxIiwgIlVBU1RvbmFsRUNNQUF2Z01heExSIiwgIlVBU1RvbmFsU0hNSW50MDVFeE1heExSIiwgIlVBU1RvbmFsU0hNSW50QXZnTWF4TFIiLCAiVUFTVG9uYWxFQ01BMDVFeE1heExSIiwgIlVBU1RvbmFsQXVyQXZnTWF4TFIiLCAiVUFTVG9uYWxBdXIwNUV4TWF4TFIiLCAiVUFTVG9uYWxBdXIxMEV4TWF4TFIiKQ0KZFZhciA8LSAiZEhpZ2hBbm5veVBjIg0KDQpzZWVkcyA8LSBjKDE1NjA4OSwgNTg2MCwgMTA1MjgsIDg5NTQxLCA0Njg1MTQ2KQ0KDQpgYGANCg0KIyMjIyMjIEh5cGVycGFyYW1ldGVyIHR1bmluZw0KDQpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTR9DQoNCnAgPC0gbXRyeVR1bmUoZGF0YUluPXN0aW1EYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZD1zZWVkc1sxXSwNCiAgICAgICAgICAgICBudHJlZXM9bnRyZWVzLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCnANCg0KYGBgDQoNClNlbGVjdGVkIGh5cGVycGFyYW1ldGVycw0KDQpgYGB7cn0NCg0KbnRyZWUgPC0gNTAxDQptdHJ5IDwtIGFzLmludGVnZXIobGVuZ3RoKGlWYXJzKS8xLjI1KQ0KDQpgYGANCg0KDQojIyMjIyMgUnVuIG1vZGVsDQoNClRyYWluIHByZWxpbWluYXJ5IG1vZGVsDQoNCmBgYHtyfQ0KIyBUb25hbGl0eQ0KDQpucGVybSA8LSA1DQoNCnJlc3VsdHNPdXRUb25hbDIgPC0gY3JmUmVnKGRhdGFJbj1zdGltRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzWzE6Ml0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICBudHJlZT1udHJlZSwgbXRyeT1tdHJ5LCBwZXJtSW1wQ29uZFRocmVzPXBlcm1JbXBDb25kVGhyZXMsIG5wZXJtPW5wZXJtLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQoNCiMgcHJpbnQgbW9kZWwgcHJlZGljdGlvbiByZXN1bHRzDQpyZXN1bHRzT3V0VG9uYWwyJE9PQl9STVNFDQpyZXN1bHRzT3V0VG9uYWwyJE9PQl9NQUUNCnJlc3VsdHNPdXRUb25hbDIkUnNxdWFyZWQNCg0KYGBgDQoNClRyYWluIG11bHRpcGxlIHNlZWRzIG1vZGVsDQoNCmBgYHtyfQ0KIyBUb25hbGl0eQ0KDQpyZXN1bHRzT3V0VG9uYWwyIDwtIG11bHRpX2NyZlJlZyhkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkcywgbnRyZWU9bnRyZWUsIG10cnk9bXRyeSwgcGVybUltcENvbmRUaHJlcz1wZXJtSW1wQ29uZFRocmVzLCBucGVybT1ucGVybSwgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQoNCiMgcHJpbnQgbW9kZWwgcHJlZGljdGlvbiByZXN1bHRzDQpyZXN1bHRzT3V0VG9uYWwyJE9PQl9STVNFDQpyZXN1bHRzT3V0VG9uYWwyJE9PQl9NQUUNCnJlc3VsdHNPdXRUb25hbDIkUnNxdWFyZWQNCg0KYGBgDQoNCg0KYGBge3J9DQoNCiMgc3RvcmUgcmVzdWx0cw0KcmVzZEhpQW5ub3lGaXRbJ0FicyB0b25hbCBubyBsb3VkJywgJ1JNU0UnXSA8LSByZXN1bHRzT3V0VG9uYWwyJE9PQl9STVNFDQpyZXNkSGlBbm5veUZpdFsnQWJzIHRvbmFsIG5vIGxvdWQnLCAnTUFFJ10gPC0gcmVzdWx0c091dFRvbmFsMiRPT0JfTUFFDQpyZXNkSGlBbm5veUZpdFsnQWJzIHRvbmFsIG5vIGxvdWQnLCAnUnNxdWFyZWQnXSA8LSByZXN1bHRzT3V0VG9uYWwyJFJzcXVhcmVkDQpyZXNkSGlBbm5veVBlcm1JbXAkQWJzVG9uYWwyIDwtIHJlc3VsdHNPdXRUb25hbDIkY29uZGl0aW9uYWxfcGVybWltcA0KDQpgYGANCg0KIyMjIyMjIFBsb3QgcmVzdWx0cw0KDQpgYGB7ciwgZmlnLndpZHRoPTgsZmlnLmhlaWdodD0zLjJ9DQpwYXIobWFpPWMoMCwzLDAsMCkpDQoNCiMgcGxvdCBjb25kaXRpb25hbCBpbXBvcnRhbmNlDQpyZXN1bHRzT3V0VG9uYWwyLmNvbmltcCA8LSBhcnJhbmdlKHJlc3VsdHNPdXRUb25hbDIkY29uZGl0aW9uYWxfcGVybWltcCwgZGVzYyhyb3dfbnVtYmVyKCkpKQ0KDQpwQmFyIDwtIGdncGxvdChyZXN1bHRzT3V0VG9uYWwyLmNvbmltcCkgKyBnZW9tX2NvbChhZXMoeD1mYWN0b3Iocm93bmFtZXMocmVzdWx0c091dFRvbmFsMi5jb25pbXApLCBsZXZlbHM9cm93bmFtZXMocmVzdWx0c091dFRvbmFsMi5jb25pbXApKSwgeT1Db25kUGVybUltcCksIGZpbGw9bXljb2xvdXJzWzNdLCB3aWR0aD0wLjUpICsgbGFicyh4PSJWYXJpYWJsZSIsIHk9IkNvbmRpdGlvbmFsIHZhcmlhYmxlIHBlcm11dGF0aW9uIGltcG9ydGFuY2UgKCUgaGlnaGx5IGFubm95ZWQpIikgKyBnZ3RpdGxlKCJUb25hbGl0eSB3L28gdG9uYWwgbG91ZG5lc3MiKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiksIHBhbmVsLmdyaWQ9ZWxlbWVudF9saW5lKGNvbG9yID0gcmdiKDIzNSwgMjM1LCAyMzUsIDEwMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksIGxpbmV3aWR0aCA9IDAuMjUsIGxpbmV0eXBlID0gMikpICsgY29vcmRfZmxpcCh5bGltPWMoLTEsIDcwKSkNCnBCYXINCg0KaWYgKHNhdmVwbG90cyl7DQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBZEhpQW5ub3lUb25hbENvblBlcm1pbXAuc3ZnIiwgd2lkdGg9OCwgaGVpZ2h0PTMuMiwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInN2ZyIpKQ0KICB1bmxpbmsoIlB0QWRIaUFubm95VG9uYWxDb25QZXJtaW1wLnN2ZyIpDQogIA0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWRIaUFubm95VG9uYWxDb25QZXJtaW1wLnBkZiIsIHdpZHRoPTgsIGhlaWdodD0zLjIsIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJwZGYiKSkNCiAgdW5saW5rKCJQdEFkSGlBbm5veVRvbmFsQ29uUGVybWltcC5wZGYiKQ0KfQ0KDQoNCmBgYA0KDQpTZWxlY3RlZCBtZXRyaWMNCg0KYGBge3J9DQoNCnRvbmFsVmFyIDwtICJVQVNUb25hbFNITUludDA1RXhNYXhMUiINCg0KYGBgDQoNCiMjIyMjIEZsdWN0dWF0aW9uIHN0cmVuZ3RoDQoNCiMjIyMjIyBTZXQgdmFyaWFibGVzDQoNCmBgYHtyfQ0KDQojIEZsdWN0dWF0aW9uIHN0cmVuZ3RoDQppVmFycyA8LSBjKGFic1ZhciwgIkFtYmllbnRMQWVxIiwgIlVBU0ZsdWN0U0hNMTBFeEJpbiIsICJVQVNGbHVjdFNITTA1RXhCaW4iLCAiVUFTRmx1Y3RGWjEwRXhNYXhMUiIsICJVQVNGbHVjdEZaMDVFeE1heExSIiwgIlVBU0ZsdWN0T1YxMEV4TWF4TFIiLCAiVUFTRmx1Y3RPVjA1RXhNYXhMUiIpDQpkVmFyIDwtICJkSGlnaEFubm95UGMiDQoNCnNlZWRzIDwtIGMoMjUxMDcsIDU0NjA5OCwgMTk1LCA1OTM3LCAxMDI2NTgpDQoNCmBgYA0KDQojIyMjIyMgSHlwZXJwYXJhbWV0ZXIgdHVuaW5nDQoNCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NH0NCg0KcCA8LSBtdHJ5VHVuZShkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkPXNlZWRzWzFdLA0KICAgICAgICAgICAgIG50cmVlcz1udHJlZXMsIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KcA0KDQpgYGANCg0KU2VsZWN0ZWQgaHlwZXJwYXJhbWV0ZXJzDQoNCmBgYHtyfQ0KDQpudHJlZSA8LSA1MDENCm10cnkgPC0gYXMuaW50ZWdlcihsZW5ndGgoaVZhcnMpLzEuMjUpDQoNCmBgYA0KDQojIyMjIyMgUnVuIG1vZGVsDQoNClRyYWluIHByZWxpbWluYXJ5IG1vZGVsDQoNCmBgYHtyfQ0KDQpucGVybSA8LSA1DQoNCnJlc3VsdHNPdXRGbHVjdCA8LSBjcmZSZWcoZGF0YUluPXN0aW1EYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHNbMToyXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgbnRyZWU9bnRyZWUsIG10cnk9bXRyeSwgcGVybUltcENvbmRUaHJlcz1wZXJtSW1wQ29uZFRocmVzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBucGVybT1ucGVybSwgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQoNCiMgcHJpbnQgbW9kZWwgcHJlZGljdGlvbiByZXN1bHRzDQpyZXN1bHRzT3V0Rmx1Y3QkT09CX1JNU0UNCnJlc3VsdHNPdXRGbHVjdCRPT0JfTUFFDQpyZXN1bHRzT3V0Rmx1Y3QkUnNxdWFyZWQNCg0KYGBgDQpUcmFpbiBtdWx0aXBsZSBzZWVkcyBtb2RlbA0KDQpgYGB7cn0NCg0KcmVzdWx0c091dEZsdWN0IDwtIG11bHRpX2NyZlJlZyhkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkcywgbnRyZWU9bnRyZWUsIG10cnk9bXRyeSwgcGVybUltcENvbmRUaHJlcz1wZXJtSW1wQ29uZFRocmVzLCBucGVybT1ucGVybSwgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQoNCiMgcHJpbnQgbW9kZWwgcHJlZGljdGlvbiByZXN1bHRzDQpyZXN1bHRzT3V0Rmx1Y3QkT09CX1JNU0UNCnJlc3VsdHNPdXRGbHVjdCRPT0JfTUFFDQpyZXN1bHRzT3V0Rmx1Y3QkUnNxdWFyZWQNCg0KYGBgDQoNCg0KYGBge3J9DQoNCiMgc3RvcmUgcmVzdWx0cw0KcmVzZEhpQW5ub3lGaXRbJ0FicyBmbHVjdCcsICdSTVNFJ10gPC0gcmVzdWx0c091dEZsdWN0JE9PQl9STVNFDQpyZXNkSGlBbm5veUZpdFsnQWJzIGZsdWN0JywgJ01BRSddIDwtIHJlc3VsdHNPdXRGbHVjdCRPT0JfTUFFDQpyZXNkSGlBbm5veUZpdFsnQWJzIGZsdWN0JywgJ1JzcXVhcmVkJ10gPC0gcmVzdWx0c091dEZsdWN0JFJzcXVhcmVkDQpyZXNkSGlBbm5veVBlcm1JbXAkQWJzRmx1Y3QgPC0gcmVzdWx0c091dEZsdWN0JGNvbmRpdGlvbmFsX3Blcm1pbXANCg0KYGBgDQoNCiMjIyMjIyBQbG90IHJlc3VsdHMNCg0KYGBge3IsIGZpZy53aWR0aD04LGZpZy5oZWlnaHQ9Mi45fQ0KcGFyKG1haT1jKDAsMywwLDApKQ0KDQojIHBsb3QgY29uZGl0aW9uYWwgaW1wb3J0YW5jZQ0KcmVzdWx0c091dEZsdWN0LmNvbmltcCA8LSBhcnJhbmdlKHJlc3VsdHNPdXRGbHVjdCRjb25kaXRpb25hbF9wZXJtaW1wLCBkZXNjKHJvd19udW1iZXIoKSkpDQoNCnBCYXIgPC0gZ2dwbG90KHJlc3VsdHNPdXRGbHVjdC5jb25pbXApICsgZ2VvbV9jb2woYWVzKHg9ZmFjdG9yKHJvd25hbWVzKHJlc3VsdHNPdXRGbHVjdC5jb25pbXApLCBsZXZlbHM9cm93bmFtZXMocmVzdWx0c091dEZsdWN0LmNvbmltcCkpLCB5PUNvbmRQZXJtSW1wKSwgZmlsbD1teWNvbG91cnNbNF0sIHdpZHRoPTAuNSkgKyBsYWJzKHg9IlZhcmlhYmxlIiwgeT0iQ29uZGl0aW9uYWwgdmFyaWFibGUgcGVybXV0YXRpb24gaW1wb3J0YW5jZSAoJSBoaWdobHkgYW5ub3llZCkiKSArIGdndGl0bGUoIkZsdWN0dWF0aW9uIHN0cmVuZ3RoIikgKyB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIpLCBwYW5lbC5ncmlkPWVsZW1lbnRfbGluZShjb2xvciA9IHJnYigyMzUsIDIzNSwgMjM1LCAxMDAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCBsaW5ld2lkdGggPSAwLjI1LCBsaW5ldHlwZSA9IDIpKSArIGNvb3JkX2ZsaXAoKQ0KcEJhcg0KDQppZiAoc2F2ZXBsb3RzKXsNCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFkSGlBbm5veUZsdWN0Q29uUGVybWltcC5zdmciLCB3aWR0aD04LCBoZWlnaHQ9Mi45LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAic3ZnIikpDQogIHVubGluaygiUHRBZEhpQW5ub3lGbHVjdENvblBlcm1pbXAuc3ZnIikNCiAgDQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBZEhpQW5ub3lGbHVjdENvblBlcm1pbXAucGRmIiwgd2lkdGg9OCwgaGVpZ2h0PTIuOSwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInBkZiIpKQ0KICB1bmxpbmsoIlB0QWRIaUFubm95Rmx1Y3RDb25QZXJtaW1wLnBkZiIpDQp9DQoNCmBgYA0KDQpTZWxlY3RlZCBtZXRyaWMNCg0KYGBge3J9DQoNCmZsdWN0VmFyIDwtICJVQVNGbHVjdE9WMTBFeE1heExSIg0KDQpgYGANCg0KIyMjIyMgUm91Z2huZXNzDQoNCiMjIyMjIyBTZXQgdmFyaWFibGVzDQoNCmBgYHtyfQ0KDQojIFJvdWdobmVzcw0KaVZhcnMgPC0gYyhhYnNWYXIsICJBbWJpZW50TEFlcSIsICJVQVNSb3VnaEVDTUExMEV4QmluIiwgIlVBU1JvdWdoRUNNQTA1RXhCaW4iLCAiVUFTUm91Z2hGWjEwRXhNYXhMUiIsICJVQVNSb3VnaEZaMDVFeE1heExSIiwgIlVBU1JvdWdoRFcxMEV4TWF4TFIiLCAiVUFTUm91Z2hEVzA1RXhNYXhMUiIpDQpkVmFyIDwtICJkSGlnaEFubm95UGMiDQoNCnNlZWRzIDwtIGMoNDcwMSwgNTIxODcsIDE2NTg5LCA2NTIxNywgMTY4OTMpDQoNCmBgYA0KDQojIyMjIyMgSHlwZXJwYXJhbWV0ZXIgdHVuaW5nDQoNCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NH0NCg0KcCA8LSBtdHJ5VHVuZShkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkPXNlZWRzWzFdLA0KICAgICAgICAgICAgIG50cmVlcz1udHJlZXMsIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KcA0KDQpgYGANCg0KU2VsZWN0ZWQgaHlwZXJwYXJhbWV0ZXJzDQoNCmBgYHtyfQ0KDQpudHJlZSA8LSA1NTAxDQptdHJ5IDwtIGFzLmludGVnZXIobGVuZ3RoKGlWYXJzKS8xLjI1KQ0KDQpgYGANCg0KDQojIyMjIyMgUnVuIG1vZGVsDQoNClRyYWluIHByZWxpbWluYXJ5IG1vZGVsDQoNCmBgYHtyfQ0KDQpucGVybSA8LSA1DQoNCnJlc3VsdHNPdXRSb3VnaCA8LSBjcmZSZWcoZGF0YUluPXN0aW1EYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHNbMToyXSwgbnRyZWU9bnRyZWUsIG10cnk9bXRyeSwgcGVybUltcENvbmRUaHJlcz1wZXJtSW1wQ29uZFRocmVzLCBucGVybT1ucGVybSwgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQoNCiMgcHJpbnQgbW9kZWwgcHJlZGljdGlvbiByZXN1bHRzDQpyZXN1bHRzT3V0Um91Z2gkT09CX1JNU0UNCnJlc3VsdHNPdXRSb3VnaCRPT0JfTUFFDQpyZXN1bHRzT3V0Um91Z2gkUnNxdWFyZWQNCg0KYGBgDQoNClRyYWluIG11bHRpcGxlIHNlZWRzIG1vZGVsDQoNCmBgYHtyfQ0KDQpyZXN1bHRzT3V0Um91Z2ggPC0gbXVsdGlfY3JmUmVnKGRhdGFJbj1zdGltRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzLCBudHJlZT1udHJlZSwgbXRyeT1tdHJ5LCBwZXJtSW1wQ29uZFRocmVzPXBlcm1JbXBDb25kVGhyZXMsIG5wZXJtPW5wZXJtLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCg0KIyBwcmludCBtb2RlbCBwcmVkaWN0aW9uIHJlc3VsdHMNCnJlc3VsdHNPdXRSb3VnaCRPT0JfUk1TRQ0KcmVzdWx0c091dFJvdWdoJE9PQl9NQUUNCnJlc3VsdHNPdXRSb3VnaCRSc3F1YXJlZA0KDQpgYGANCg0KYGBge3J9DQojIHN0b3JlIHJlc3VsdHMNCnJlc2RIaUFubm95Rml0WydBYnMgcm91Z2gnLCAnUk1TRSddIDwtIHJlc3VsdHNPdXRSb3VnaCRPT0JfUk1TRQ0KcmVzZEhpQW5ub3lGaXRbJ0FicyByb3VnaCcsICdNQUUnXSA8LSByZXN1bHRzT3V0Um91Z2gkT09CX01BRQ0KcmVzZEhpQW5ub3lGaXRbJ0FicyByb3VnaCcsICdSc3F1YXJlZCddIDwtIHJlc3VsdHNPdXRSb3VnaCRSc3F1YXJlZA0KcmVzZEhpQW5ub3lQZXJtSW1wJEFic1JvdWdoIDwtIHJlc3VsdHNPdXRSb3VnaCRjb25kaXRpb25hbF9wZXJtaW1wDQoNCmBgYA0KDQojIyMjIyMgUGxvdCByZXN1bHRzDQoNCmBgYHtyLCBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTIuOX0NCnBhcihtYWk9YygwLDMsMCwwKSkNCg0KIyBwbG90IGNvbmRpdGlvbmFsIGltcG9ydGFuY2UNCnJlc3VsdHNPdXRSb3VnaC5jb25pbXAgPC0gYXJyYW5nZShyZXN1bHRzT3V0Um91Z2gkY29uZGl0aW9uYWxfcGVybWltcCwgZGVzYyhyb3dfbnVtYmVyKCkpKQ0KDQpwQmFyIDwtIGdncGxvdChyZXN1bHRzT3V0Um91Z2guY29uaW1wKSArIGdlb21fY29sKGFlcyh4PWZhY3Rvcihyb3duYW1lcyhyZXN1bHRzT3V0Um91Z2guY29uaW1wKSwgbGV2ZWxzPXJvd25hbWVzKHJlc3VsdHNPdXRSb3VnaC5jb25pbXApKSwgeT1Db25kUGVybUltcCksIGZpbGw9bXljb2xvdXJzWzVdLCB3aWR0aD0wLjUpICsgbGFicyh4PSJWYXJpYWJsZSIsIHk9IkNvbmRpdGlvbmFsIHZhcmlhYmxlIHBlcm11dGF0aW9uIGltcG9ydGFuY2UgKCUgaGlnaGx5IGFubm95ZWQpIikgKyBnZ3RpdGxlKCJSb3VnaG5lc3MiKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiksIHBhbmVsLmdyaWQ9ZWxlbWVudF9saW5lKGNvbG9yID0gcmdiKDIzNSwgMjM1LCAyMzUsIDEwMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksIGxpbmV3aWR0aCA9IDAuMjUsIGxpbmV0eXBlID0gMikpICsgY29vcmRfZmxpcCgpDQpwQmFyDQoNCmlmIChzYXZlcGxvdHMpew0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWRIaUFubm95Um91Z2hDb25QZXJtaW1wLnN2ZyIsIHdpZHRoPTgsIGhlaWdodD0yLjksIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJzdmciKSkNCiAgdW5saW5rKCJQdEFkSGlBbm5veVJvdWdoQ29uUGVybWltcC5zdmciKQ0KICANCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFkSGlBbm5veVJvdWdoQ29uUGVybWltcC5wZGYiLCB3aWR0aD04LCBoZWlnaHQ9Mi45LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAicGRmIikpDQogIHVubGluaygiUHRBZEhpQW5ub3lSb3VnaENvblBlcm1pbXAucGRmIikNCn0NCg0KDQpgYGANCg0KU2VsZWN0ZWQgbWV0cmljDQoNCmBgYHtyfQ0KDQpyb3VnaFZhciA8LSAiVUFTUm91Z2hGWjA1RXhNYXhMUiINCg0KYGBgDQoNCg0KIyMjIyMgSW1wdWxzaXZlbmVzcw0KDQojIyMjIyMgU2V0IHZhcmlhYmxlcw0KDQpgYGB7cn0NCiMgSW1wdWxzaXZlbmVzcw0KaVZhcnMgPC0gYyhhYnNWYXIsICJBbWJpZW50TEFlcSIsICJVQVNJbXB1bHNTSE1BdmdNYXhMUiIsICJVQVNJbXB1bHNTSE0wNUV4TWF4TFIiLCAiVUFTSW1wdWxzU0hNUG93QXZnTWF4TFIiKQ0KZFZhciA8LSAiZEhpZ2hBbm5veVBjIg0KDQpzZWVkcyA8LSBjKDg0OTUsIDU5ODY3LCA1NDE2LCA5ODQzLCA4NikNCg0KYGBgDQoNCiMjIyMjIyBIeXBlcnBhcmFtZXRlciB0dW5pbmcNCg0KYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD00fQ0KDQpwIDwtIG10cnlUdW5lKGRhdGFJbj1zdGltRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWQ9c2VlZHNbMV0sDQogICAgICAgICAgICAgbnRyZWVzPW50cmVlcywgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQpwDQoNCmBgYA0KDQpTZWxlY3RlZCBoeXBlcnBhcmFtZXRlcnMNCg0KYGBge3J9DQoNCm50cmVlIDwtIDE1MDENCm10cnkgPC0gYXMuaW50ZWdlcihsZW5ndGgoaVZhcnMpLzEuMjUpDQoNCmBgYA0KDQoNCiMjIyMjIyBSdW4gbW9kZWwNCg0KVHJhaW4gcHJlbGltaW5hcnkgbW9kZWwNCg0KYGBge3J9DQoNCm5wZXJtIDwtIDUNCg0KcmVzdWx0c091dEltcHVscyA8LSBjcmZSZWcoZGF0YUluPXN0aW1EYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHNbMToyXSwgbnRyZWU9bnRyZWUsIG10cnk9bXRyeSwgcGVybUltcENvbmRUaHJlcz1wZXJtSW1wQ29uZFRocmVzLCBucGVybT1ucGVybSwgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQoNCiMgcHJpbnQgbW9kZWwgcHJlZGljdGlvbiByZXN1bHRzDQpyZXN1bHRzT3V0SW1wdWxzJE9PQl9STVNFDQpyZXN1bHRzT3V0SW1wdWxzJE9PQl9NQUUNCnJlc3VsdHNPdXRJbXB1bHMkUnNxdWFyZWQNCg0KYGBgDQoNClRyYWluIG11bHRpcGxlIHNlZWRzIG1vZGVsDQoNCmBgYHtyfQ0KDQpyZXN1bHRzT3V0SW1wdWxzIDwtIG11bHRpX2NyZlJlZyhkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkcywgbnRyZWU9bnRyZWUsIG10cnk9bXRyeSwgcGVybUltcENvbmRUaHJlcz1wZXJtSW1wQ29uZFRocmVzLCBucGVybT1ucGVybSwgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQoNCiMgcHJpbnQgbW9kZWwgcHJlZGljdGlvbiByZXN1bHRzDQpyZXN1bHRzT3V0SW1wdWxzJE9PQl9STVNFDQpyZXN1bHRzT3V0SW1wdWxzJE9PQl9NQUUNCnJlc3VsdHNPdXRJbXB1bHMkUnNxdWFyZWQNCg0KYGBgDQoNCmBgYHtyfQ0KDQojIHN0b3JlIHJlc3VsdHMNCnJlc2RIaUFubm95Rml0WydBYnMgaW1wdWxzJywgJ1JNU0UnXSA8LSByZXN1bHRzT3V0SW1wdWxzJE9PQl9STVNFDQpyZXNkSGlBbm5veUZpdFsnQWJzIGltcHVscycsICdNQUUnXSA8LSByZXN1bHRzT3V0SW1wdWxzJE9PQl9NQUUNCnJlc2RIaUFubm95Rml0WydBYnMgaW1wdWxzJywgJ1JzcXVhcmVkJ10gPC0gcmVzdWx0c091dEltcHVscyRSc3F1YXJlZA0KcmVzZEhpQW5ub3lQZXJtSW1wJEFic0ltcHVscyA8LSByZXN1bHRzT3V0SW1wdWxzJGNvbmRpdGlvbmFsX3Blcm1pbXANCg0KYGBgDQoNCiMjIyMjIyBQbG90IHJlc3VsdHMNCg0KYGBge3IsIGZpZy53aWR0aD04LGZpZy5oZWlnaHQ9Mn0NCnBhcihtYWk9YygwLDMsMCwwKSkNCg0KIyBwbG90IGNvbmRpdGlvbmFsIGltcG9ydGFuY2UNCnJlc3VsdHNPdXRJbXB1bHMuY29uaW1wIDwtIGFycmFuZ2UocmVzdWx0c091dEltcHVscyRjb25kaXRpb25hbF9wZXJtaW1wLCBkZXNjKHJvd19udW1iZXIoKSkpDQoNCnBCYXIgPC0gZ2dwbG90KHJlc3VsdHNPdXRJbXB1bHMuY29uaW1wKSArIGdlb21fY29sKGFlcyh4PWZhY3Rvcihyb3duYW1lcyhyZXN1bHRzT3V0SW1wdWxzLmNvbmltcCksIGxldmVscz1yb3duYW1lcyhyZXN1bHRzT3V0SW1wdWxzLmNvbmltcCkpLCB5PUNvbmRQZXJtSW1wKSwgZmlsbD1teWNvbG91cnNbNl0sIHdpZHRoPTAuNSkgKyBsYWJzKHg9IlZhcmlhYmxlIiwgeT0iQ29uZGl0aW9uYWwgdmFyaWFibGUgcGVybXV0YXRpb24gaW1wb3J0YW5jZSAoJSBoaWdobHkgYW5ub3llZCkiKSArIGdndGl0bGUoIkltcHVsc2l2ZW5lc3MiKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiksIHBhbmVsLmdyaWQ9ZWxlbWVudF9saW5lKGNvbG9yID0gcmdiKDIzNSwgMjM1LCAyMzUsIDEwMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksIGxpbmV3aWR0aCA9IDAuMjUsIGxpbmV0eXBlID0gMikpICsgY29vcmRfZmxpcCgpDQpwQmFyDQoNCmlmIChzYXZlcGxvdHMpew0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWRIaUFubm95SW1wdWxzQ29uUGVybWltcC5zdmciLCB3aWR0aD04LCBoZWlnaHQ9MiwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInN2ZyIpKQ0KICB1bmxpbmsoIlB0QWRIaUFubm95SW1wdWxzQ29uUGVybWltcC5zdmciKQ0KICANCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFkSGlBbm5veUltcHVsc0NvblBlcm1pbXAucGRmIiwgd2lkdGg9OCwgaGVpZ2h0PTIsIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJwZGYiKSkNCiAgdW5saW5rKCJQdEFkSGlBbm5veUltcHVsc0NvblBlcm1pbXAucGRmIikNCn0NCg0KYGBgDQoNClNlbGVjdGVkIG1ldHJpYw0KDQpgYGB7cn0NCg0KaW1wdWxzVmFyIDwtICJVQVNJbXB1bHNTSE1BdmdNYXhMUiINCg0KYGBgDQoNCiMjIyMgU1FNIGFuZCBsb3VkbmVzcyBjb21wYXJpc29uDQoNCk5vdyB0aGUgaGlnaGVzdCBpbXBvcnRhbmNlIFNRTXMgYXJlIHJhbmtlZCBhZ2FpbnN0IGVhY2ggb3RoZXIsIGNvbnRyb2xsaW5nIGZvciBVQVMgbG91ZG5lc3MgYW5kIGFtYmllbnQgTEFlcS4NCg0KIyMjIyMgSW5jbHVkZSB0b25hbCBsb3VkbmVzcw0KDQojIyMjIyMgU2V0IHZhcmlhYmxlcw0KDQpgYGB7cn0NCg0KaVZhcnMgPC0gYyhhYnNWYXIsICJBbWJpZW50TEFlcSIsIHNoYXJwVmFyLCB0b25MZFZhciwgZmx1Y3RWYXIsIHJvdWdoVmFyLCBpbXB1bHNWYXIpDQpkVmFyIDwtICJkSGlnaEFubm95UGMiDQoNCnNlZWRzIDwtIGMoNzA0OTgsIDQsIDE0OTg2LCA0NTMsIDg2NCkNCg0KYGBgDQoNCiMjIyMjIyBIeXBlcnBhcmFtZXRlciB0dW5pbmcNCg0KYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD00fQ0KDQpwIDwtIG10cnlUdW5lKGRhdGFJbj1zdGltRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWQ9c2VlZHNbMV0sDQogICAgICAgICAgICAgbnRyZWVzPW50cmVlcywgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQpwDQoNCmBgYA0KDQpTZWxlY3RlZCBoeXBlcnBhcmFtZXRlcnMNCg0KYGBge3J9DQoNCm50cmVlIDwtIDU1MDENCm10cnkgPC0gYXMuaW50ZWdlcihsZW5ndGgoaVZhcnMpLzEuMjUpDQoNCmBgYA0KDQoNCiMjIyMjIyBSdW4gbW9kZWwNCg0KVHJhaW4gcHJlbGltaW5hcnkgbW9kZWwNCg0KYGBge3J9DQoNCm5wZXJtIDwtIDUNCg0KcmVzdWx0c091dFNRTXMxIDwtIGNyZlJlZyhkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkc1sxOjJdLCBudHJlZT1udHJlZSwgbXRyeT1tdHJ5LCBwZXJtSW1wQ29uZFRocmVzPXBlcm1JbXBDb25kVGhyZXMsIG5wZXJtPW5wZXJtLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCg0KIyBwcmludCBtb2RlbCBwcmVkaWN0aW9uIHJlc3VsdHMNCnJlc3VsdHNPdXRTUU1zMSRPT0JfUk1TRQ0KcmVzdWx0c091dFNRTXMxJE9PQl9NQUUNCnJlc3VsdHNPdXRTUU1zMSRSc3F1YXJlZA0KDQpgYGANCg0KVHJhaW4gbXVsdGlwbGUgc2VlZHMgbW9kZWwNCg0KYGBge3J9DQoNCnJlc3VsdHNPdXRTUU1zMSA8LSBtdWx0aV9jcmZSZWcoZGF0YUluPXN0aW1EYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHMsIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dFNRTXMxJE9PQl9STVNFDQpyZXN1bHRzT3V0U1FNczEkT09CX01BRQ0KcmVzdWx0c091dFNRTXMxJFJzcXVhcmVkDQoNCmBgYA0KDQpgYGB7cn0NCg0KIyBzdG9yZSByZXN1bHRzDQpyZXNkSGlBbm5veUZpdFsnQWJzIFNRTXMgaW5jIHRvbmFsIGxvdWQnLCAnUk1TRSddIDwtIHJlc3VsdHNPdXRTUU1zMSRPT0JfUk1TRQ0KcmVzZEhpQW5ub3lGaXRbJ0FicyBTUU1zIGluYyB0b25hbCBsb3VkJywgJ01BRSddIDwtIHJlc3VsdHNPdXRTUU1zMSRPT0JfTUFFDQpyZXNkSGlBbm5veUZpdFsnQWJzIFNRTXMgaW5jIHRvbmFsIGxvdWQnLCAnUnNxdWFyZWQnXSA8LSByZXN1bHRzT3V0U1FNczEkUnNxdWFyZWQNCnJlc2RIaUFubm95UGVybUltcCRBYnNTUU1zMSA8LSByZXN1bHRzT3V0U1FNczEkY29uZGl0aW9uYWxfcGVybWltcA0KDQpgYGANCg0KIyMjIyMjIFBsb3QgcmVzdWx0cw0KDQpgYGB7ciwgZmlnLndpZHRoPTgsZmlnLmhlaWdodD0yLjR9DQpwYXIobWFpPWMoMCwzLDAsMCkpDQoNCiMgcGxvdCBjb25kaXRpb25hbCBpbXBvcnRhbmNlDQpyZXN1bHRzT3V0U1FNczEuY29uaW1wIDwtIGFycmFuZ2UocmVzdWx0c091dFNRTXMxJGNvbmRpdGlvbmFsX3Blcm1pbXAsIGRlc2Mocm93X251bWJlcigpKSkNCg0KcEJhciA8LSBnZ3Bsb3QocmVzdWx0c091dFNRTXMxLmNvbmltcCkgKyBnZW9tX2NvbChhZXMoeD1mYWN0b3Iocm93bmFtZXMocmVzdWx0c091dFNRTXMxLmNvbmltcCksIGxldmVscz1yb3duYW1lcyhyZXN1bHRzT3V0U1FNczEuY29uaW1wKSksIHk9Q29uZFBlcm1JbXApLCBmaWxsPW15Y29sb3Vyc1s3XSwgd2lkdGg9MC41KSArIGxhYnMoeD0iVmFyaWFibGUiLCB5PSJDb25kaXRpb25hbCB2YXJpYWJsZSBwZXJtdXRhdGlvbiBpbXBvcnRhbmNlICglIGhpZ2hseSBhbm5veWVkKSIpICsgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2VyaWYiKSwgcGFuZWwuZ3JpZD1lbGVtZW50X2xpbmUoY29sb3IgPSByZ2IoMjM1LCAyMzUsIDIzNSwgMTAwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgbGluZXdpZHRoID0gMC4yNSwgbGluZXR5cGUgPSAyKSkgKyBjb29yZF9mbGlwKHlsaW09YygtMSwgNTApKQ0KcEJhcg0KDQppZiAoc2F2ZXBsb3RzKXsNCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFkSGlBbm5veUFic1NRTXNUb25MZENvblBlcm1pbXAuc3ZnIiwgd2lkdGg9OCwgaGVpZ2h0PTIuNCwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInN2ZyIpKQ0KICB1bmxpbmsoIlB0QWRIaUFubm95QWJzU1FNc1RvbkxkQ29uUGVybWltcC5zdmciKQ0KICANCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFkSGlBbm5veUFic1NRTXNUb25MZENvblBlcm1pbXAucGRmIiwgd2lkdGg9OCwgaGVpZ2h0PTIuNCwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInBkZiIpKQ0KICB1bmxpbmsoIlB0QWRIaUFubm95QWJzU1FNc1RvbkxkQ29uUGVybWltcC5wZGYiKQ0KfQ0KDQpgYGANCg0KIyMjIyMgRXhjbHVkZSB0b25hbCBsb3VkbmVzcw0KDQojIyMjIyMgU2V0IHZhcmlhYmxlcw0KDQpgYGB7cn0NCg0KaVZhcnMgPC0gYyhhYnNWYXIsICJBbWJpZW50TEFlcSIsIHNoYXJwVmFyLCB0b25hbFZhciwgZmx1Y3RWYXIsIHJvdWdoVmFyLCBpbXB1bHNWYXIpDQpkVmFyIDwtICJkSGlnaEFubm95UGMiDQoNCnNlZWRzIDwtIGMoNTQ2LCA1NzIwMywgMjcwODM1LCA2MDU5MiwgODA5NCkNCg0KYGBgDQoNCiMjIyMjIyBIeXBlcnBhcmFtZXRlciB0dW5pbmcNCg0KYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD00fQ0KDQpwIDwtIG10cnlUdW5lKGRhdGFJbj1zdGltRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWQ9c2VlZHNbMV0sDQogICAgICAgICAgICAgbnRyZWVzPW50cmVlcywgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQpwDQoNCmBgYA0KDQpTZWxlY3RlZCBoeXBlcnBhcmFtZXRlcnMNCg0KYGBge3J9DQoNCm50cmVlIDwtIDU1MDENCm10cnkgPC0gYXMuaW50ZWdlcihsZW5ndGgoaVZhcnMpLzEuMjUpDQoNCmBgYA0KDQoNCiMjIyMjIyBSdW4gbW9kZWwNCg0KVHJhaW4gcHJlbGltaW5hcnkgbW9kZWwNCg0KYGBge3J9DQoNCm5wZXJtIDwtIDUNCg0KcmVzdWx0c091dFNRTXMyIDwtIGNyZlJlZyhkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkc1sxOjJdLCBudHJlZT1udHJlZSwgbXRyeT1tdHJ5LCBwZXJtSW1wQ29uZFRocmVzPXBlcm1JbXBDb25kVGhyZXMsIG5wZXJtPW5wZXJtLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCg0KIyBwcmludCBtb2RlbCBwcmVkaWN0aW9uIHJlc3VsdHMNCnJlc3VsdHNPdXRTUU1zMiRPT0JfUk1TRQ0KcmVzdWx0c091dFNRTXMyJE9PQl9NQUUNCnJlc3VsdHNPdXRTUU1zMiRSc3F1YXJlZA0KDQpgYGANCg0KVHJhaW4gbXVsdGlwbGUgc2VlZHMgbW9kZWwNCg0KYGBge3J9DQoNCnJlc3VsdHNPdXRTUU1zMiA8LSBtdWx0aV9jcmZSZWcoZGF0YUluPXN0aW1EYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHMsIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dFNRTXMyJE9PQl9STVNFDQpyZXN1bHRzT3V0U1FNczIkT09CX01BRQ0KcmVzdWx0c091dFNRTXMyJFJzcXVhcmVkDQoNCmBgYA0KDQpgYGB7cn0NCg0KIyBzdG9yZSByZXN1bHRzDQpyZXNkSGlBbm5veUZpdFsnQWJzIFNRTXMgbm8gdG9uYWwgbG91ZCcsICdSTVNFJ10gPC0gcmVzdWx0c091dFNRTXMyJE9PQl9STVNFDQpyZXNkSGlBbm5veUZpdFsnQWJzIFNRTXMgbm8gdG9uYWwgbG91ZCcsICdSTVNFJ10gPC0gcmVzdWx0c091dFNRTXMyJE9PQl9NQUUNCnJlc2RIaUFubm95Rml0WydBYnMgU1FNcyBubyB0b25hbCBsb3VkJywgJ1JzcXVhcmVkJ10gPC0gcmVzdWx0c091dFNRTXMyJFJzcXVhcmVkDQpyZXNkSGlBbm5veVBlcm1JbXAkQWJzU1FNczIgPC0gcmVzdWx0c091dFNRTXMyJGNvbmRpdGlvbmFsX3Blcm1pbXANCg0KYGBgDQoNCiMjIyMjIyBQbG90IHJlc3VsdHMNCg0KYGBge3IsIGZpZy53aWR0aD04LGZpZy5oZWlnaHQ9Mi40fQ0KcGFyKG1haT1jKDAsMywwLDApKQ0KDQojIHBsb3QgY29uZGl0aW9uYWwgaW1wb3J0YW5jZQ0KcmVzdWx0c091dFNRTXMyLmNvbmltcCA8LSBhcnJhbmdlKHJlc3VsdHNPdXRTUU1zMiRjb25kaXRpb25hbF9wZXJtaW1wLCBkZXNjKHJvd19udW1iZXIoKSkpDQoNCnBCYXIgPC0gZ2dwbG90KHJlc3VsdHNPdXRTUU1zMi5jb25pbXApICsgZ2VvbV9jb2woYWVzKHg9ZmFjdG9yKHJvd25hbWVzKHJlc3VsdHNPdXRTUU1zMi5jb25pbXApLCBsZXZlbHM9cm93bmFtZXMocmVzdWx0c091dFNRTXMyLmNvbmltcCkpLCB5PUNvbmRQZXJtSW1wKSwgZmlsbD1teWNvbG91cnNbN10sIHdpZHRoPTAuNSkgKyBsYWJzKHg9IlZhcmlhYmxlIiwgeT0iQ29uZGl0aW9uYWwgdmFyaWFibGUgcGVybXV0YXRpb24gaW1wb3J0YW5jZSAoJSBoaWdobHkgYW5ub3llZCkiKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiksIHBhbmVsLmdyaWQ9ZWxlbWVudF9saW5lKGNvbG9yID0gcmdiKDIzNSwgMjM1LCAyMzUsIDEwMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksIGxpbmV3aWR0aCA9IDAuMjUsIGxpbmV0eXBlID0gMikpICsgY29vcmRfZmxpcCh5bGltPWMoLTEsIDUwKSkNCnBCYXINCg0KaWYgKHNhdmVwbG90cyl7DQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBZEhpQW5ub3lBYnNTUU1zTm9Ub25MZENvblBlcm1pbXAuc3ZnIiwgd2lkdGg9OCwgaGVpZ2h0PTIuNCwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInN2ZyIpKQ0KICB1bmxpbmsoIlB0QWRIaUFubm95QWJzU1FNc05vVG9uTGRDb25QZXJtaW1wLnN2ZyIpDQogIA0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWRIaUFubm95QWJzU1FNc05vVG9uTGRDb25QZXJtaW1wLnBkZiIsIHdpZHRoPTgsIGhlaWdodD0yLjQsIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJwZGYiKSkNCiAgdW5saW5rKCJQdEFkSGlBbm5veUFic1NRTXNOb1RvbkxkQ29uUGVybWltcC5wZGYiKQ0KfQ0KDQpgYGANCg0KIyMjIERpZmZlcmVuY2UgdmFyaWFibGVzDQoNCk5leHQsIHRoZSBkaWZmZXJlbmNlIG1ldHJpY3MgYXJlIGFuYWx5c2VkLCANCg0KIyMjIyBSZW1vdmUgYW1iaWVudCBvbmx5IHN0aW11bGkNCg0KSGVyZSwgdGhlICdhbWJpZW50IG9ubHknIHN0aW11bGkgYXJlIHJlbW92ZWQsIGFzIHRoZSBhbmFseXNpcyBjYW5ub3QgaGFuZGxlIG1pc3NpbmcgdmFsdWVzIGZvciBkQiBtZXRyaWNzLg0KDQpgYGB7cn0NCnN0aW1EYXRhQU51bSA8LSBzdGltRGF0YUFOdW1bY29tcGxldGUuY2FzZXMoc3RpbURhdGFBTnVtKSxdDQpzdGltRGF0YUFOdW0kVUFTTEFlcSA8LSBhcy5udW1lcmljKHN0aW1EYXRhQU51bSRVQVNMQWVxKQ0Kc3RpbURhdGFBTnVtJFNOUmxldmVsIDwtIGFzLm51bWVyaWMoc3RpbURhdGFBTnVtJFNOUmxldmVsKQ0KYGBgDQoNCiMjIyMgU2V0IHZhcmlhYmxlcw0KDQpgYGB7cn0NCg0KaVZhcnMgPC0gYyhuYW1lcyhzdGltRGF0YUFOdW0pW3doaWNoKGNvbG5hbWVzKHN0aW1EYXRhQU51bSk9PSJMQWVxTEFGOTBkaWZmIik6DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2hpY2goY29sbmFtZXMoc3RpbURhdGFBTnVtKT09ImRJbXB1bHNTSE0wNUV4TWF4TFIiKV0sICJTTlJsZXZlbCIpDQpkVmFyIDwtICJkSGlnaEFubm95UGMiDQoNCnNlZWRzIDwtIGMoNTY4MzkyLCA0OTgsIDQwODksIDc4MTMyLCA3NDE4MDkpDQoNCmBgYA0KDQojIyMjIEh5cGVycGFyYW1ldGVyIHR1bmluZw0KDQpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTR9DQoNCnAgPC0gbXRyeVR1bmUoZGF0YUluPXN0aW1EYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZD1zZWVkc1sxXSwNCiAgICAgICAgICAgICBudHJlZXM9bnRyZWVzLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCnANCg0KYGBgDQoNClNlbGVjdGVkIGh5cGVycGFyYW1ldGVycw0KDQpgYGB7cn0NCg0KbnRyZWUgPC0gNDAwMQ0KbXRyeSA8LSBhcy5pbnRlZ2VyKGxlbmd0aChpVmFycykvMi4yNSkNCg0KYGBgDQoNCiMjIyMgUnVuIG1vZGVsDQoNClRyYWluIHByZWxpbWluYXJ5IG1vZGVsDQoNCmBgYHtyfQ0KDQpucGVybSA8LSAzMA0KDQpyZXN1bHRzT3V0RGlmZnMgPC0gY3JmUmVnKGRhdGFJbj1zdGltRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzWzE6Ml0sIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dERpZmZzJE9PQl9STVNFDQpyZXN1bHRzT3V0RGlmZnMkT09CX01BRQ0KcmVzdWx0c091dERpZmZzJFJzcXVhcmVkDQoNCmBgYA0KDQpUcmFpbiBtdWx0aXBsZSBzZWVkcyBtb2RlbA0KDQpgYGB7cn0NCg0KcmVzdWx0c091dERpZmZzIDwtIG11bHRpX2NyZlJlZyhkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkcywgbnRyZWU9bnRyZWUsIG10cnk9bXRyeSwgcGVybUltcENvbmRUaHJlcz1wZXJtSW1wQ29uZFRocmVzLCBucGVybT1ucGVybSwgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQoNCiMgcHJpbnQgbW9kZWwgcHJlZGljdGlvbiByZXN1bHRzDQpyZXN1bHRzT3V0RGlmZnMkT09CX1JNU0UNCnJlc3VsdHNPdXREaWZmcyRPT0JfTUFFDQpyZXN1bHRzT3V0RGlmZnMkUnNxdWFyZWQNCg0KYGBgDQoNCmBgYHtyfQ0KDQojIHN0b3JlIHJlc3VsdHMNCnJlc2RIaUFubm95Rml0WydEaWZmIHZhcnMnLCAnUk1TRSddIDwtIHJlc3VsdHNPdXREaWZmcyRPT0JfUk1TRQ0KcmVzZEhpQW5ub3lGaXRbJ0RpZmYgdmFycycsICdNQUUnXSA8LSByZXN1bHRzT3V0RGlmZnMkT09CX01BRQ0KcmVzZEhpQW5ub3lGaXRbJ0RpZmYgdmFycycsICdSc3F1YXJlZCddIDwtIHJlc3VsdHNPdXREaWZmcyRSc3F1YXJlZA0KcmVzZEhpQW5ub3lQZXJtSW1wJERpZmZWYXJzIDwtIHJlc3VsdHNPdXREaWZmcyRjb25kaXRpb25hbF9wZXJtaW1wDQoNCmBgYA0KDQojIyMjIFBsb3QgcmVzdWx0cw0KDQpgYGB7ciwgZmlnLndpZHRoPTgsZmlnLmhlaWdodD0xMH0NCnBhcihtYWk9YygwLDMsMCwwKSkNCg0KIyBwbG90IGNvbmRpdGlvbmFsIGltcG9ydGFuY2UNCnJlc3VsdHNPdXREaWZmcy5jb25pbXAgPC0gYXJyYW5nZShyZXN1bHRzT3V0RGlmZnMkY29uZGl0aW9uYWxfcGVybWltcCwgZGVzYyhyb3dfbnVtYmVyKCkpKQ0KDQpwQmFyIDwtIGdncGxvdChyZXN1bHRzT3V0RGlmZnMuY29uaW1wKSArIGdlb21fY29sKGFlcyh4PWZhY3Rvcihyb3duYW1lcyhyZXN1bHRzT3V0RGlmZnMuY29uaW1wKSwgbGV2ZWxzPXJvd25hbWVzKHJlc3VsdHNPdXREaWZmcy5jb25pbXApKSwgeT1Db25kUGVybUltcCksIGZpbGw9bXljb2xvdXJzWzhdLCB3aWR0aD0wLjUpICsgbGFicyh4PSJWYXJpYWJsZSIsIHk9IkNvbmRpdGlvbmFsIHZhcmlhYmxlIHBlcm11dGF0aW9uIGltcG9ydGFuY2UgKCUgaGlnaGx5IGFubm95ZWQpIikgKyB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIpLCBwYW5lbC5ncmlkPWVsZW1lbnRfbGluZShjb2xvciA9IHJnYigyMzUsIDIzNSwgMjM1LCAxMDAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCBsaW5ld2lkdGggPSAwLjI1LCBsaW5ldHlwZSA9IDIpKSArIGNvb3JkX2ZsaXAoKQ0KcEJhcg0KDQppZiAoc2F2ZXBsb3RzKXsNCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFkSGlBbm5veURpZmZWYXJzQ29uUGVybWltcC5zdmciLCB3aWR0aD04LCBoZWlnaHQ9MTAsIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJzdmciKSkNCiAgdW5saW5rKCJQdEFkSGlBbm5veURpZmZWYXJzQ29uUGVybWltcC5zdmciKQ0KICANCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFkSGlBbm5veURpZmZWYXJzQ29uUGVybWltcC5wZGYiLCB3aWR0aD04LCBoZWlnaHQ9MTAsIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJwZGYiKSkNCiAgdW5saW5rKCJQdEFkSGlBbm5veURpZmZWYXJzQ29uUGVybWltcC5wZGYiKQ0KfQ0KDQpgYGANCmBgYHtyLCBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTh9DQoNCiMgUGxvdCBvbmx5IHBvc2l0aXZlIHZhbHVlcw0KcmVzdWx0c091dERpZmZzLmNvbmltcFB0diA8LSByZXN1bHRzT3V0RGlmZnMuY29uaW1wIHw+DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93bmFtZXNfdG9fY29sdW1uKCdNZXRyaWMnKSB8Pg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXJfaWYoaXMubnVtZXJpYywgYWxsX3ZhcnMoLiA+IDApKSB8Pg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2x1bW5fdG9fcm93bmFtZXMoJ01ldHJpYycpDQoNCnBCYXIgPC0gZ2dwbG90KHJlc3VsdHNPdXREaWZmcy5jb25pbXBQdHYpICsgZ2VvbV9jb2woYWVzKHg9ZmFjdG9yKHJvd25hbWVzKHJlc3VsdHNPdXREaWZmcy5jb25pbXBQdHYpLCBsZXZlbHM9cm93bmFtZXMocmVzdWx0c091dERpZmZzLmNvbmltcFB0dikpLCB5PUNvbmRQZXJtSW1wKSwgZmlsbD1teWNvbG91cnNbOF0sIHdpZHRoPTAuNSkgKyBsYWJzKHg9IlZhcmlhYmxlIiwgeT0iQ29uZGl0aW9uYWwgdmFyaWFibGUgcGVybXV0YXRpb24gaW1wb3J0YW5jZSAoJSBoaWdobHkgYW5ub3llZCkiKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiksIHBhbmVsLmdyaWQ9ZWxlbWVudF9saW5lKGNvbG9yID0gcmdiKDIzNSwgMjM1LCAyMzUsIDEwMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksIGxpbmV3aWR0aCA9IDAuMjUsIGxpbmV0eXBlID0gMikpICsgY29vcmRfZmxpcCgpDQpwQmFyDQoNCmlmIChzYXZlcGxvdHMpew0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWRIaUFubm95RGlmZlZhcnNDb25QZXJtaW1wUHR2LnN2ZyIsIHdpZHRoPTgsIGhlaWdodD04LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAic3ZnIikpDQogIHVubGluaygiUHRBZEhpQW5ub3lEaWZmVmFyc0NvblBlcm1pbXBQdHYuc3ZnIikNCiAgDQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBZEhpQW5ub3lEaWZmVmFyc0NvblBlcm1pbXBQdHYucGRmIiwgd2lkdGg9OCwgaGVpZ2h0PTgsIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJwZGYiKSkNCiAgdW5saW5rKCJQdEFkSGlBbm5veURpZmZWYXJzQ29uUGVybWltcFB0di5wZGYiKQ0KfQ0KDQpgYGANCg0KU2VsZWN0ZWQgbWV0cmljDQoNCmBgYHtyfQ0KDQpkaWZmVmFyIDwtICJFUE5MTEFlcWRpZmYiDQoNCmBgYA0KDQojIyMgZFNRTSBhbmFseXNpcw0KDQpUaGUgYW1iaWVudC1vbmx5IHN0aW11bGkgYXJlIE5PVCByZXBsYWNlZCBoZXJlLCBhcyB0aGUgZGlmZmVyZW5jZSBhbmFseXNpcyBpbmNsdWRlcyBkQiBtZXRyaWNzLg0KDQojIyMjIEluZGl2aWR1YWwgU1FNcw0KDQojIyMjIyBkU2hhcnBuZXNzDQoNCiMjIyMjIyBTZXQgdmFyaWFibGVzDQoNCmBgYHtyfQ0KDQppVmFycyA8LSBjKGRpZmZWYXIsICJkU2hhcnBBdXJJU08zUG93QXZnTWF4TFIiLCAiZFNoYXJwQXVySVNPMzA1RXhNYXhMUiIsICJkU2hhcnBBdXJTSE1Qb3dBdmdNYXhMUiIsICJkU2hhcnBBdXJTSE0wNUV4TWF4TFIiKQ0KZFZhciA8LSAiZEhpZ2hBbm5veVBjIg0KDQpzZWVkcyA8LSBjKDg0MTk0LCA5MDUsIDY0ODE1LCA5MjgwNTQsIDYyNTA5MSwgNTgyMDMxKQ0KDQpgYGANCg0KIyMjIyMjIEh5cGVycGFyYW1ldGVyIHR1bmluZw0KDQpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTR9DQoNCnAgPC0gbXRyeVR1bmUoZGF0YUluPXN0aW1EYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZD1zZWVkc1sxXSwNCiAgICAgICAgICAgICBudHJlZXM9bnRyZWVzLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCnANCg0KYGBgDQoNClNlbGVjdGVkIGh5cGVycGFyYW1ldGVycw0KDQpgYGB7cn0NCg0KbnRyZWUgPC0gMTUwMQ0KbXRyeSA8LSBhcy5pbnRlZ2VyKGxlbmd0aChpVmFycykvMS4yNSkNCg0KYGBgDQoNCg0KIyMjIyMjIFJ1biBtb2RlbA0KDQpUcmFpbiBwcmVsaW1pbmFyeSBtb2RlbA0KDQpgYGB7cn0NCg0KbnBlcm0gPC0gNQ0KDQpyZXN1bHRzT3V0U2hhcnAgPC0gY3JmUmVnKGRhdGFJbj1zdGltRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzWzE6Ml0sIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dFNoYXJwJE9PQl9STVNFDQpyZXN1bHRzT3V0U2hhcnAkT09CX01BRQ0KcmVzdWx0c091dFNoYXJwJFJzcXVhcmVkDQoNCmBgYA0KVHJhaW4gbXVsdGlwbGUgc2VlZHMgbW9kZWwNCg0KYGBge3J9DQoNCnJlc3VsdHNPdXRTaGFycCA8LSBtdWx0aV9jcmZSZWcoZGF0YUluPXN0aW1EYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHMsIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dFNoYXJwJE9PQl9STVNFDQpyZXN1bHRzT3V0U2hhcnAkT09CX01BRQ0KcmVzdWx0c091dFNoYXJwJFJzcXVhcmVkDQoNCmBgYA0KDQoNCmBgYHtyfQ0KIyBzdG9yZSByZXN1bHRzDQpyZXNkSGlBbm5veUZpdFsnRGlmZiBzaGFycCcsICdSTVNFJ10gPC0gcmVzdWx0c091dFNoYXJwJE9PQl9STVNFDQpyZXNkSGlBbm5veUZpdFsnRGlmZiBzaGFycCcsICdNQUUnXSA8LSByZXN1bHRzT3V0U2hhcnAkT09CX01BRQ0KcmVzZEhpQW5ub3lGaXRbJ0RpZmYgc2hhcnAnLCAnUnNxdWFyZWQnXSA8LSByZXN1bHRzT3V0U2hhcnAkUnNxdWFyZWQNCnJlc2RIaUFubm95UGVybUltcCREaWZmU2hhcnAgPC0gcmVzdWx0c091dFNoYXJwJGNvbmRpdGlvbmFsX3Blcm1pbXANCg0KYGBgDQoNCiMjIyMjIyBQbG90IHJlc3VsdHMNCg0KYGBge3IsIGZpZy53aWR0aD04LGZpZy5oZWlnaHQ9Mi42fQ0KcGFyKG1haT1jKDAsMywwLDApKQ0KDQojIHBsb3QgY29uZGl0aW9uYWwgaW1wb3J0YW5jZQ0KcmVzdWx0c091dFNoYXJwLmNvbmltcCA8LSBhcnJhbmdlKHJlc3VsdHNPdXRTaGFycCRjb25kaXRpb25hbF9wZXJtaW1wLCBkZXNjKHJvd19udW1iZXIoKSkpDQoNCnBCYXIgPC0gZ2dwbG90KHJlc3VsdHNPdXRTaGFycC5jb25pbXApICsgZ2VvbV9jb2woYWVzKHg9ZmFjdG9yKHJvd25hbWVzKHJlc3VsdHNPdXRTaGFycC5jb25pbXApLCBsZXZlbHM9cm93bmFtZXMocmVzdWx0c091dFNoYXJwLmNvbmltcCkpLCB5PUNvbmRQZXJtSW1wKSwgZmlsbD1teWNvbG91cnNbMl0sIHdpZHRoPTAuNSkgKyBsYWJzKHg9IlZhcmlhYmxlIiwgeT0iQ29uZGl0aW9uYWwgdmFyaWFibGUgcGVybXV0YXRpb24gaW1wb3J0YW5jZSAoJSBoaWdobHkgYW5ub3llZCkiKSArIGdndGl0bGUoImRTaGFycG5lc3MiKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiksIHBhbmVsLmdyaWQ9ZWxlbWVudF9saW5lKGNvbG9yID0gcmdiKDIzNSwgMjM1LCAyMzUsIDEwMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksIGxpbmV3aWR0aCA9IDAuMjUsIGxpbmV0eXBlID0gMikpICsgY29vcmRfZmxpcCgpDQpwQmFyDQoNCmlmIChzYXZlcGxvdHMpew0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWRIaUFubm95ZFNoYXJwQ29uUGVybWltcC5zdmciLCB3aWR0aD04LCBoZWlnaHQ9Mi42LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAic3ZnIikpDQogIHVubGluaygiUHRBZEhpQW5ub3lkU2hhcnBDb25QZXJtaW1wLnN2ZyIpDQogIA0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWRIaUFubm95ZFNoYXJwQ29uUGVybWltcC5wZGYiLCB3aWR0aD04LCBoZWlnaHQ9Mi42LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAicGRmIikpDQogIHVubGluaygiUHRBZEhpQW5ub3lkU2hhcnBDb25QZXJtaW1wLnBkZiIpDQp9DQoNCg0KYGBgDQoNClNlbGVjdGVkIG1ldHJpYw0KDQpgYGB7cn0NCg0KZFNoYXJwVmFyIDwtICJkU2hhcnBBdXJTSE1Qb3dBdmdNYXhMUiINCg0KYGBgDQoNCg0KIyMjIyMgZFRvbmFsIGxvdWRuZXNzIGFuZCBkdG9uYWxpdHkNCg0KIyMjIyMjIFNldCB2YXJpYWJsZXMNCg0KYGBge3J9DQoNCmlWYXJzIDwtIGMoZGlmZlZhciwgImRUb25hbEVDTUFBdmdNYXhMUiIsICJkVG9uYWxTSE1JbnQwNUV4TWF4TFIiLCAiZFRvbmFsU0hNSW50QXZnTWF4TFIiLCAiZFRvbmFsRUNNQTA1RXhNYXhMUiIsICJkVG9uTGRFQ01BUG93QXZnQmluIiwgImRUb25MZEVDTUEwNUV4QmluIikNCmRWYXIgPC0gImRIaWdoQW5ub3lQYyINCg0KYGBgDQoNCiMjIyMjIyBIeXBlcnBhcmFtZXRlciB0dW5pbmcNCg0KYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD00fQ0KDQpwIDwtIG10cnlUdW5lKGRhdGFJbj1zdGltRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWQ9c2VlZHNbMV0sDQogICAgICAgICAgICAgbnRyZWVzPW50cmVlcywgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQpwDQoNCnNlZWRzIDwtIGMoNTYxNjg0LCAxMDQ3OTgsIDE1MzYsIDQ4LCA0ODU2MSkNCg0KYGBgDQpTZWxlY3RlZCBoeXBlcnBhcmFtZXRlcnMNCg0KYGBge3J9DQoNCm50cmVlIDwtIDE1MDENCm10cnkgPC0gYXMuaW50ZWdlcihsZW5ndGgoaVZhcnMpLzEuMjUpDQoNCmBgYA0KDQojIyMjIyMgUnVuIG1vZGVsDQoNClRyYWluIHByZWxpbWluYXJ5IG1vZGVsDQoNCmBgYHtyfQ0KIyBUb25hbGl0eSB3aXRoIHRvbmFsIGxvdWRuZXNzDQoNCm5wZXJtIDwtIDUNCg0KcmVzdWx0c091dFRvbmFsMSA8LSBjcmZSZWcoZGF0YUluPXN0aW1EYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHNbMToyXSwgbnRyZWU9bnRyZWUsIG10cnk9bXRyeSwgcGVybUltcENvbmRUaHJlcz1wZXJtSW1wQ29uZFRocmVzLCBucGVybT1ucGVybSwgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQoNCiMgcHJpbnQgbW9kZWwgcHJlZGljdGlvbiByZXN1bHRzDQpyZXN1bHRzT3V0VG9uYWwxJE9PQl9STVNFDQpyZXN1bHRzT3V0VG9uYWwxJE9PQl9NQUUNCnJlc3VsdHNPdXRUb25hbDEkUnNxdWFyZWQNCmBgYA0KDQpUcmFpbiBtdWx0aXBsZSBzZWVkcyBtb2RlbA0KDQpgYGB7cn0NCiMgVG9uYWxpdHkgd2l0aCB0b25hbCBsb3VkbmVzcw0KDQpyZXN1bHRzT3V0VG9uYWwxIDwtIG11bHRpX2NyZlJlZyhkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkcywgbnRyZWU9bnRyZWUsIG10cnk9bXRyeSwgcGVybUltcENvbmRUaHJlcz1wZXJtSW1wQ29uZFRocmVzLCBucGVybT1ucGVybSwgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQoNCiMgcHJpbnQgbW9kZWwgcHJlZGljdGlvbiByZXN1bHRzDQpyZXN1bHRzT3V0VG9uYWwxJE9PQl9STVNFDQpyZXN1bHRzT3V0VG9uYWwxJE9PQl9NQUUNCnJlc3VsdHNPdXRUb25hbDEkUnNxdWFyZWQNCg0KYGBgDQoNCmBgYHtyfQ0KIyBzdG9yZSByZXN1bHRzDQpyZXNkSGlBbm5veUZpdFsnRGlmZiB0b25hbCBpbmMgbG91ZCcsICdSTVNFJ10gPC0gcmVzdWx0c091dFRvbmFsMSRPT0JfUk1TRQ0KcmVzZEhpQW5ub3lGaXRbJ0RpZmYgdG9uYWwgaW5jIGxvdWQnLCAnTUFFJ10gPC0gcmVzdWx0c091dFRvbmFsMSRPT0JfTUFFDQpyZXNkSGlBbm5veUZpdFsnRGlmZiB0b25hbCBpbmMgbG91ZCcsICdSc3F1YXJlZCddIDwtIHJlc3VsdHNPdXRUb25hbDEkUnNxdWFyZWQNCnJlc2RIaUFubm95UGVybUltcCREaWZmVG9uYWwxIDwtIHJlc3VsdHNPdXRUb25hbDEkY29uZGl0aW9uYWxfcGVybWltcA0KDQpgYGANCg0KIyMjIyMjIFBsb3QgcmVzdWx0cw0KDQpgYGB7ciwgZmlnLndpZHRoPTgsZmlnLmhlaWdodD0yLjZ9DQoNCnBhcihtYWk9YygwLDMsMCwwKSkNCg0KIyBwbG90IGNvbmRpdGlvbmFsIGltcG9ydGFuY2UNCnJlc3VsdHNPdXRUb25hbDEuY29uaW1wIDwtIGFycmFuZ2UocmVzdWx0c091dFRvbmFsMSRjb25kaXRpb25hbF9wZXJtaW1wLCBkZXNjKHJvd19udW1iZXIoKSkpDQoNCnBCYXIgPC0gZ2dwbG90KHJlc3VsdHNPdXRUb25hbDEuY29uaW1wKSArIGdlb21fY29sKGFlcyh4PWZhY3Rvcihyb3duYW1lcyhyZXN1bHRzT3V0VG9uYWwxLmNvbmltcCksIGxldmVscz1yb3duYW1lcyhyZXN1bHRzT3V0VG9uYWwxLmNvbmltcCkpLCB5PUNvbmRQZXJtSW1wKSwgZmlsbD1teWNvbG91cnNbM10sIHdpZHRoPTAuNSkgKyBsYWJzKHg9IlZhcmlhYmxlIiwgeT0iQ29uZGl0aW9uYWwgdmFyaWFibGUgcGVybXV0YXRpb24gaW1wb3J0YW5jZSAoJSBoaWdobHkgYW5ub3llZCkiKSArIGdndGl0bGUoImRUb25hbGl0eSBpbmMuIGR0b25hbCBsb3VkbmVzcyIpICsgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2VyaWYiKSwgcGFuZWwuZ3JpZD1lbGVtZW50X2xpbmUoY29sb3IgPSByZ2IoMjM1LCAyMzUsIDIzNSwgMTAwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgbGluZXdpZHRoID0gMC4yNSwgbGluZXR5cGUgPSAyKSkgKyBjb29yZF9mbGlwKHlsaW09YygwLCA3MCkpDQpwQmFyDQoNCmlmIChzYXZlcGxvdHMpew0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWRIaUFubm95ZFRvbmFsTGRDb25QZXJtaW1wLnN2ZyIsIHdpZHRoPTgsIGhlaWdodD0yLjYsIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJzdmciKSkNCiAgdW5saW5rKCJQdEFkSGlBbm5veWRUb25hbExkQ29uUGVybWltcC5zdmciKQ0KICANCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFkSGlBbm5veWRUb25hbExkQ29uUGVybWltcC5wZGYiLCB3aWR0aD04LCBoZWlnaHQ9Mi42LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAicGRmIikpDQogIHVubGluaygiUHRBZEhpQW5ub3lkVG9uYWxMZENvblBlcm1pbXAucGRmIikNCn0NCg0KYGBgDQoNClNlbGVjdGVkIG1ldHJpYw0KDQpgYGB7cn0NCg0KZFRvbkxkVmFyIDwtICJkVG9uTGRFQ01BUG93QXZnQmluIg0KDQpgYGANCg0KIyMjIyMgZFRvbmFsaXR5IHdpdGhvdXQgZHRvbmFsIGxvdWRuZXNzDQoNCiMjIyMjIyBTZXQgdmFyaWFibGVzDQoNCmBgYHtyfQ0KDQppVmFycyA8LSBjKGRpZmZWYXIsICJkVG9uYWxFQ01BQXZnTWF4TFIiLCAiZFRvbmFsU0hNSW50MDVFeE1heExSIiwgImRUb25hbFNITUludEF2Z01heExSIiwgImRUb25hbEVDTUEwNUV4TWF4TFIiKQ0KZFZhciA8LSAiZEhpZ2hBbm5veVBjIg0KDQpzZWVkcyA8LSBjKDQxMDg2NSwgMjk1NCwgNzA4MTIsIDIwMywgNzk4NCkNCg0KYGBgDQoNCiMjIyMjIyBIeXBlcnBhcmFtZXRlciB0dW5pbmcNCg0KYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD00fQ0KDQpwIDwtIG10cnlUdW5lKGRhdGFJbj1zdGltRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWQ9c2VlZHNbMV0sDQogICAgICAgICAgICAgbnRyZWVzPW50cmVlcywgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQpwDQoNCg0KYGBgDQoNClNlbGVjdGVkIGh5cGVycGFyYW1ldGVycw0KDQpgYGB7cn0NCg0KbnRyZWUgPC0gNTUwMQ0KbXRyeSA8LSBhcy5pbnRlZ2VyKGxlbmd0aChpVmFycykvMS4yNSkNCg0KYGBgDQoNCg0KIyMjIyMjIFJ1biBtb2RlbA0KDQpUcmFpbiBwcmVsaW1pbmFyeSBtb2RlbA0KDQpgYGB7cn0NCiMgVG9uYWxpdHkNCg0KbnBlcm0gPC0gNQ0KDQpyZXN1bHRzT3V0VG9uYWwyIDwtIGNyZlJlZyhkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkc1sxOjJdLCBudHJlZT1udHJlZSwgbXRyeT1tdHJ5LCBwZXJtSW1wQ29uZFRocmVzPXBlcm1JbXBDb25kVGhyZXMsIG5wZXJtPW5wZXJtLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCg0KIyBwcmludCBtb2RlbCBwcmVkaWN0aW9uIHJlc3VsdHMNCnJlc3VsdHNPdXRUb25hbDIkT09CX1JNU0UNCnJlc3VsdHNPdXRUb25hbDIkT09CX01BRQ0KcmVzdWx0c091dFRvbmFsMiRSc3F1YXJlZA0KDQpgYGANCg0KVHJhaW4gbXVsdGlwbGUgc2VlZHMgbW9kZWwNCg0KYGBge3J9DQojIFRvbmFsaXR5DQoNCnJlc3VsdHNPdXRUb25hbDIgPC0gbXVsdGlfY3JmUmVnKGRhdGFJbj1zdGltRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzLCBudHJlZT1udHJlZSwgbXRyeT1tdHJ5LCBwZXJtSW1wQ29uZFRocmVzPXBlcm1JbXBDb25kVGhyZXMsIG5wZXJtPW5wZXJtLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCg0KIyBwcmludCBtb2RlbCBwcmVkaWN0aW9uIHJlc3VsdHMNCnJlc3VsdHNPdXRUb25hbDIkT09CX1JNU0UNCnJlc3VsdHNPdXRUb25hbDIkT09CX01BRQ0KcmVzdWx0c091dFRvbmFsMiRSc3F1YXJlZA0KDQpgYGANCg0KDQpgYGB7cn0NCg0KIyBzdG9yZSByZXN1bHRzDQpyZXNkSGlBbm5veUZpdFsnRGlmZiB0b25hbCBubyBsb3VkJywgJ1JNU0UnXSA8LSByZXN1bHRzT3V0VG9uYWwyJE9PQl9STVNFDQpyZXNkSGlBbm5veUZpdFsnRGlmZiB0b25hbCBubyBsb3VkJywgJ01BRSddIDwtIHJlc3VsdHNPdXRUb25hbDIkT09CX01BRQ0KcmVzZEhpQW5ub3lGaXRbJ0RpZmYgdG9uYWwgbm8gbG91ZCcsICdSc3F1YXJlZCddIDwtIHJlc3VsdHNPdXRUb25hbDIkUnNxdWFyZWQNCnJlc2RIaUFubm95UGVybUltcCREaWZmVG9uYWwyIDwtIHJlc3VsdHNPdXRUb25hbDIkY29uZGl0aW9uYWxfcGVybWltcA0KDQpgYGANCg0KIyMjIyMjIFBsb3QgcmVzdWx0cw0KDQpgYGB7ciwgZmlnLndpZHRoPTgsZmlnLmhlaWdodD0yfQ0KcGFyKG1haT1jKDAsMywwLDApKQ0KDQojIHBsb3QgY29uZGl0aW9uYWwgaW1wb3J0YW5jZQ0KcmVzdWx0c091dFRvbmFsMi5jb25pbXAgPC0gYXJyYW5nZShyZXN1bHRzT3V0VG9uYWwyJGNvbmRpdGlvbmFsX3Blcm1pbXAsIGRlc2Mocm93X251bWJlcigpKSkNCg0KcEJhciA8LSBnZ3Bsb3QocmVzdWx0c091dFRvbmFsMi5jb25pbXApICsgZ2VvbV9jb2woYWVzKHg9ZmFjdG9yKHJvd25hbWVzKHJlc3VsdHNPdXRUb25hbDIuY29uaW1wKSwgbGV2ZWxzPXJvd25hbWVzKHJlc3VsdHNPdXRUb25hbDIuY29uaW1wKSksIHk9Q29uZFBlcm1JbXApLCBmaWxsPW15Y29sb3Vyc1szXSwgd2lkdGg9MC41KSArIGxhYnMoeD0iVmFyaWFibGUiLCB5PSJDb25kaXRpb25hbCB2YXJpYWJsZSBwZXJtdXRhdGlvbiBpbXBvcnRhbmNlICglIGhpZ2hseSBhbm5veWVkKSIpICsgZ2d0aXRsZSgiZFRvbmFsaXR5IHcvbyB0b25hbCBsb3VkbmVzcyIpICsgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2VyaWYiKSwgcGFuZWwuZ3JpZD1lbGVtZW50X2xpbmUoY29sb3IgPSByZ2IoMjM1LCAyMzUsIDIzNSwgMTAwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgbGluZXdpZHRoID0gMC4yNSwgbGluZXR5cGUgPSAyKSkgKyBjb29yZF9mbGlwKHlsaW09YygwLCA3MCkpDQpwQmFyDQoNCmlmIChzYXZlcGxvdHMpew0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWRIaUFubm95ZFRvbmFsQ29uUGVybWltcC5zdmciLCB3aWR0aD04LCBoZWlnaHQ9MiwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInN2ZyIpKQ0KICB1bmxpbmsoIlB0QWRIaUFubm95ZFRvbmFsQ29uUGVybWltcC5zdmciKQ0KICANCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFkSGlBbm5veWRUb25hbENvblBlcm1pbXAucGRmIiwgd2lkdGg9OCwgaGVpZ2h0PTIsIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJwZGYiKSkNCiAgdW5saW5rKCJQdEFkSGlBbm5veWRUb25hbENvblBlcm1pbXAucGRmIikNCn0NCg0KDQpgYGANCg0KU2VsZWN0ZWQgbWV0cmljDQoNCmBgYHtyfQ0KDQpkVG9uYWxWYXIgPC0gImRUb25hbFNITUludEF2Z01heExSIg0KDQpgYGANCg0KIyMjIyMgZEZsdWN0dWF0aW9uIHN0cmVuZ3RoDQoNCiMjIyMjIyBTZXQgdmFyaWFibGVzDQoNCmBgYHtyfQ0KDQojIEZsdWN0dWF0aW9uIHN0cmVuZ3RoDQppVmFycyA8LSBjKGRpZmZWYXIsICJkRmx1Y3RTSE0xMEV4QmluIiwgImRGbHVjdFNITTA1RXhCaW4iLCAiZEZsdWN0T1YxMEV4TWF4TFIiLCAiZEZsdWN0T1YwNUV4TWF4TFIiKQ0KZFZhciA8LSAiZEhpZ2hBbm5veVBjIg0KDQpzZWVkcyA8LSBjKDQxODY1NywgODQsIDE2MzAsIDE4NjU5LCAzNjg3KQ0KDQpgYGANCg0KDQojIyMjIyMgSHlwZXJwYXJhbWV0ZXIgdHVuaW5nDQoNCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NH0NCg0KcCA8LSBtdHJ5VHVuZShkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkPXNlZWRzWzFdLA0KICAgICAgICAgICAgIG50cmVlcz1udHJlZXMsIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KcA0KDQpgYGANCg0KU2VsZWN0ZWQgaHlwZXJwYXJhbWV0ZXJzDQoNCmBgYHtyfQ0KDQpudHJlZSA8LSAyNTENCm10cnkgPC0gYXMuaW50ZWdlcihsZW5ndGgoaVZhcnMpLzEuMjUpDQoNCmBgYA0KDQojIyMjIyMgUnVuIG1vZGVsDQoNClRyYWluIHByZWxpbWluYXJ5IG1vZGVsDQoNCmBgYHtyfQ0KDQpucGVybSA8LSA1DQoNCnJlc3VsdHNPdXRGbHVjdCA8LSBjcmZSZWcoZGF0YUluPXN0aW1EYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHNbMToyXSwgbnRyZWU9bnRyZWUsIG10cnk9bXRyeSwgcGVybUltcENvbmRUaHJlcz1wZXJtSW1wQ29uZFRocmVzLCBucGVybT1ucGVybSwgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQoNCiMgcHJpbnQgbW9kZWwgcHJlZGljdGlvbiByZXN1bHRzDQpyZXN1bHRzT3V0Rmx1Y3QkT09CX1JNU0UNCnJlc3VsdHNPdXRGbHVjdCRPT0JfTUFFDQpyZXN1bHRzT3V0Rmx1Y3QkUnNxdWFyZWQNCg0KYGBgDQoNClRyYWluIG11bHRpcGxlIHNlZWRzIG1vZGVsDQoNCmBgYHtyfQ0KDQpyZXN1bHRzT3V0Rmx1Y3QgPC0gbXVsdGlfY3JmUmVnKGRhdGFJbj1zdGltRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzLCBudHJlZT1udHJlZSwgbXRyeT1tdHJ5LCBwZXJtSW1wQ29uZFRocmVzPXBlcm1JbXBDb25kVGhyZXMsIG5wZXJtPW5wZXJtLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCg0KIyBwcmludCBtb2RlbCBwcmVkaWN0aW9uIHJlc3VsdHMNCnJlc3VsdHNPdXRGbHVjdCRPT0JfUk1TRQ0KcmVzdWx0c091dEZsdWN0JE9PQl9NQUUNCnJlc3VsdHNPdXRGbHVjdCRSc3F1YXJlZA0KDQpgYGANCg0KDQpgYGB7cn0NCg0KIyBzdG9yZSByZXN1bHRzDQpyZXNkSGlBbm5veUZpdFsnRGlmZiBmbHVjdCcsICdSTVNFJ10gPC0gcmVzdWx0c091dEZsdWN0JE9PQl9STVNFDQpyZXNkSGlBbm5veUZpdFsnRGlmZiBmbHVjdCcsICdNQUUnXSA8LSByZXN1bHRzT3V0Rmx1Y3QkT09CX01BRQ0KcmVzZEhpQW5ub3lGaXRbJ0RpZmYgZmx1Y3QnLCAnUnNxdWFyZWQnXSA8LSByZXN1bHRzT3V0Rmx1Y3QkUnNxdWFyZWQNCnJlc2RIaUFubm95UGVybUltcCREaWZmRmx1Y3QgPC0gcmVzdWx0c091dEZsdWN0JGNvbmRpdGlvbmFsX3Blcm1pbXANCg0KYGBgDQoNCiMjIyMjIyBQbG90IHJlc3VsdHMNCg0KYGBge3IsIGZpZy53aWR0aD04LGZpZy5oZWlnaHQ9Mn0NCnBhcihtYWk9YygwLDMsMCwwKSkNCg0KIyBwbG90IGNvbmRpdGlvbmFsIGltcG9ydGFuY2UNCnJlc3VsdHNPdXRGbHVjdC5jb25pbXAgPC0gYXJyYW5nZShyZXN1bHRzT3V0Rmx1Y3QkY29uZGl0aW9uYWxfcGVybWltcCwgZGVzYyhyb3dfbnVtYmVyKCkpKQ0KDQpwQmFyIDwtIGdncGxvdChyZXN1bHRzT3V0Rmx1Y3QuY29uaW1wKSArIGdlb21fY29sKGFlcyh4PWZhY3Rvcihyb3duYW1lcyhyZXN1bHRzT3V0Rmx1Y3QuY29uaW1wKSwgbGV2ZWxzPXJvd25hbWVzKHJlc3VsdHNPdXRGbHVjdC5jb25pbXApKSwgeT1Db25kUGVybUltcCksIGZpbGw9bXljb2xvdXJzWzRdLCB3aWR0aD0wLjUpICsgbGFicyh4PSJWYXJpYWJsZSIsIHk9IkNvbmRpdGlvbmFsIHZhcmlhYmxlIHBlcm11dGF0aW9uIGltcG9ydGFuY2UgKCUgaGlnaGx5IGFubm95ZWQpIikgKyBnZ3RpdGxlKCJkRmx1Y3R1YXRpb24gc3RyZW5ndGgiKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiksIHBhbmVsLmdyaWQ9ZWxlbWVudF9saW5lKGNvbG9yID0gcmdiKDIzNSwgMjM1LCAyMzUsIDEwMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksIGxpbmV3aWR0aCA9IDAuMjUsIGxpbmV0eXBlID0gMikpICsgY29vcmRfZmxpcCgpDQpwQmFyDQoNCmlmIChzYXZlcGxvdHMpew0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWRIaUFubm95ZEZsdWN0Q29uUGVybWltcC5zdmciLCB3aWR0aD04LCBoZWlnaHQ9MiwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInN2ZyIpKQ0KICB1bmxpbmsoIlB0QWRIaUFubm95Rmx1Y3RDb25QZXJtaW1wLnN2ZyIpDQogIA0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWRIaUFubm95ZEZsdWN0Q29uUGVybWltcC5wZGYiLCB3aWR0aD04LCBoZWlnaHQ9MiwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInBkZiIpKQ0KICB1bmxpbmsoIlB0QWRIaUFubm95Rmx1Y3RDb25QZXJtaW1wLnBkZiIpDQp9DQoNCmBgYA0KDQpTZWxlY3RlZCBtZXRyaWMNCg0KYGBge3J9DQoNCmRGbHVjdFZhciA8LSAiZEZsdWN0U0hNMTBFeEJpbiINCg0KYGBgDQoNCiMjIyMjIGRSb3VnaG5lc3MNCg0KIyMjIyMjIFNldCB2YXJpYWJsZXMNCg0KYGBge3J9DQoNCiMgUm91Z2huZXNzDQppVmFycyA8LSBjKGRpZmZWYXIsICJkUm91Z2hFQ01BMTBFeEJpbiIsICJkUm91Z2hFQ01BMDVFeEJpbiIsICJkUm91Z2hGWjEwRXhNYXhMUiIsICJkUm91Z2hGWjA1RXhNYXhMUiIpDQpkVmFyIDwtICJkSGlnaEFubm95UGMiDQoNCnNlZWRzIDwtIGMoNjk4NTEsIDg1MTA5LCA0MTA5ODYsIDE1NjMsIDg5NikNCg0KYGBgDQoNCiMjIyMjIyBIeXBlcnBhcmFtZXRlciB0dW5pbmcNCg0KYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD00fQ0KDQpwIDwtIG10cnlUdW5lKGRhdGFJbj1zdGltRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWQ9c2VlZHNbMV0sDQogICAgICAgICAgICAgbnRyZWVzPW50cmVlcywgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQpwDQoNCmBgYA0KDQpTZWxlY3RlZCBoeXBlcnBhcmFtZXRlcnMNCg0KYGBge3J9DQoNCm50cmVlIDwtIDUwMQ0KbXRyeSA8LSBhcy5pbnRlZ2VyKGxlbmd0aChpVmFycykvMS4yNSkNCg0KYGBgDQoNCiMjIyMjIyBSdW4gbW9kZWwNCg0KVHJhaW4gcHJlbGltaW5hcnkgbW9kZWwNCg0KYGBge3J9DQoNCm5wZXJtIDwtIDUNCg0KcmVzdWx0c091dFJvdWdoIDwtIGNyZlJlZyhkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkc1sxOjJdLCBudHJlZT1udHJlZSwgbXRyeT1tdHJ5LCBwZXJtSW1wQ29uZFRocmVzPXBlcm1JbXBDb25kVGhyZXMsIG5wZXJtPW5wZXJtLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCg0KIyBwcmludCBtb2RlbCBwcmVkaWN0aW9uIHJlc3VsdHMNCnJlc3VsdHNPdXRSb3VnaCRPT0JfUk1TRQ0KcmVzdWx0c091dFJvdWdoJE9PQl9NQUUNCnJlc3VsdHNPdXRSb3VnaCRSc3F1YXJlZA0KDQpgYGANCg0KVHJhaW4gbXVsdGlwbGUgc2VlZHMgbW9kZWwNCg0KYGBge3J9DQoNCnJlc3VsdHNPdXRSb3VnaCA8LSBtdWx0aV9jcmZSZWcoZGF0YUluPXN0aW1EYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHMsIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dFJvdWdoJE9PQl9STVNFDQpyZXN1bHRzT3V0Um91Z2gkT09CX01BRQ0KcmVzdWx0c091dFJvdWdoJFJzcXVhcmVkDQoNCmBgYA0KDQpgYGB7cn0NCiMgc3RvcmUgcmVzdWx0cw0KcmVzZEhpQW5ub3lGaXRbJ0RpZmYgcm91Z2gnLCAnUk1TRSddIDwtIHJlc3VsdHNPdXRSb3VnaCRPT0JfUk1TRQ0KcmVzZEhpQW5ub3lGaXRbJ0RpZmYgcm91Z2gnLCAnTUFFJ10gPC0gcmVzdWx0c091dFJvdWdoJE9PQl9NQUUNCnJlc2RIaUFubm95Rml0WydEaWZmIHJvdWdoJywgJ1JzcXVhcmVkJ10gPC0gcmVzdWx0c091dFJvdWdoJFJzcXVhcmVkDQpyZXNkSGlBbm5veVBlcm1JbXAkRGlmZlJvdWdoIDwtIHJlc3VsdHNPdXRSb3VnaCRjb25kaXRpb25hbF9wZXJtaW1wDQoNCmBgYA0KDQojIyMjIyMgUGxvdCByZXN1bHRzDQoNCmBgYHtyLCBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTJ9DQpwYXIobWFpPWMoMCwzLDAsMCkpDQoNCiMgcGxvdCBjb25kaXRpb25hbCBpbXBvcnRhbmNlDQpyZXN1bHRzT3V0Um91Z2guY29uaW1wIDwtIGFycmFuZ2UocmVzdWx0c091dFJvdWdoJGNvbmRpdGlvbmFsX3Blcm1pbXAsIGRlc2Mocm93X251bWJlcigpKSkNCg0KcEJhciA8LSBnZ3Bsb3QocmVzdWx0c091dFJvdWdoLmNvbmltcCkgKyBnZW9tX2NvbChhZXMoeD1mYWN0b3Iocm93bmFtZXMocmVzdWx0c091dFJvdWdoLmNvbmltcCksIGxldmVscz1yb3duYW1lcyhyZXN1bHRzT3V0Um91Z2guY29uaW1wKSksIHk9Q29uZFBlcm1JbXApLCBmaWxsPW15Y29sb3Vyc1s1XSwgd2lkdGg9MC41KSArIGxhYnMoeD0iVmFyaWFibGUiLCB5PSJDb25kaXRpb25hbCB2YXJpYWJsZSBwZXJtdXRhdGlvbiBpbXBvcnRhbmNlICglIGhpZ2hseSBhbm5veWVkKSIpICsgZ2d0aXRsZSgiZFJvdWdobmVzcyIpICsgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2VyaWYiKSwgcGFuZWwuZ3JpZD1lbGVtZW50X2xpbmUoY29sb3IgPSByZ2IoMjM1LCAyMzUsIDIzNSwgMTAwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgbGluZXdpZHRoID0gMC4yNSwgbGluZXR5cGUgPSAyKSkgKyBjb29yZF9mbGlwKCkNCnBCYXINCg0KaWYgKHNhdmVwbG90cyl7DQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBZEhpQW5ub3lkUm91Z2hDb25QZXJtaW1wLnN2ZyIsIHdpZHRoPTgsIGhlaWdodD0yLCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAic3ZnIikpDQogIHVubGluaygiUHRBZEhpQW5ub3lkUm91Z2hDb25QZXJtaW1wLnN2ZyIpDQogIA0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWRIaUFubm95ZFJvdWdoQ29uUGVybWltcC5wZGYiLCB3aWR0aD04LCBoZWlnaHQ9MiwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInBkZiIpKQ0KICB1bmxpbmsoIlB0QWRIaUFubm95ZFJvdWdoQ29uUGVybWltcC5wZGYiKQ0KfQ0KDQoNCmBgYA0KDQpTZWxlY3RlZCBtZXRyaWMNCg0KYGBge3J9DQoNCmRSb3VnaFZhciA8LSAiZFJvdWdoRlowNUV4TWF4TFIiDQoNCmBgYA0KDQojIyMjIyBkSW1wdWxzaXZlbmVzcw0KDQojIyMjIyMgU2V0IHZhcmlhYmxlcw0KDQpgYGB7cn0NCiMgSW1wdWxzaXZlbmVzcw0KaVZhcnMgPC0gYyhkaWZmVmFyLCAiZEltcHVsc1NITUF2Z01heExSIiwgImRJbXB1bHNTSE0wNUV4TWF4TFIiLCAiZEltcHVsc1NITVBvd0F2Z01heExSIikNCmRWYXIgPC0gImRIaWdoQW5ub3lQYyINCg0Kc2VlZHMgPC0gYyg0MTg2NTksIDc4MDUsIDM4NDc1LCA2NTgzNCwgMTY1MykNCg0KYGBgDQoNCiMjIyMjIyBIeXBlcnBhcmFtZXRlciB0dW5pbmcNCg0KYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD00fQ0KDQpwIDwtIG10cnlUdW5lKGRhdGFJbj1zdGltRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWQ9c2VlZHNbMV0sDQogICAgICAgICAgICAgbnRyZWVzPW50cmVlcywgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQpwDQoNCmBgYA0KDQpTZWxlY3RlZCBoeXBlcnBhcmFtZXRlcnMNCg0KYGBge3J9DQoNCm50cmVlIDwtIDI1MDENCm10cnkgPC0gYXMuaW50ZWdlcihsZW5ndGgoaVZhcnMpLzEuMjUpDQoNCmBgYA0KDQoNCiMjIyMjIyBSdW4gbW9kZWwNCg0KVHJhaW4gcHJlbGltaW5hcnkgbW9kZWwNCg0KYGBge3J9DQoNCm5wZXJtIDwtIDUNCg0KcmVzdWx0c091dEltcHVscyA8LSBjcmZSZWcoZGF0YUluPXN0aW1EYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHNbMToyXSwgbnRyZWU9bnRyZWUsIG10cnk9bXRyeSwgcGVybUltcENvbmRUaHJlcz1wZXJtSW1wQ29uZFRocmVzLCBucGVybT1ucGVybSwgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQoNCiMgcHJpbnQgbW9kZWwgcHJlZGljdGlvbiByZXN1bHRzDQpyZXN1bHRzT3V0SW1wdWxzJE9PQl9STVNFDQpyZXN1bHRzT3V0SW1wdWxzJE9PQl9NQUUNCnJlc3VsdHNPdXRJbXB1bHMkUnNxdWFyZWQNCg0KYGBgDQoNClRyYWluIG11bHRpcGxlIHNlZWRzIG1vZGVsDQoNCmBgYHtyfQ0KDQpyZXN1bHRzT3V0SW1wdWxzIDwtIG11bHRpX2NyZlJlZyhkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkcywgbnRyZWU9bnRyZWUsIG10cnk9bXRyeSwgcGVybUltcENvbmRUaHJlcz1wZXJtSW1wQ29uZFRocmVzLCBucGVybT1ucGVybSwgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQoNCiMgcHJpbnQgbW9kZWwgcHJlZGljdGlvbiByZXN1bHRzDQpyZXN1bHRzT3V0SW1wdWxzJE9PQl9STVNFDQpyZXN1bHRzT3V0SW1wdWxzJE9PQl9NQUUNCnJlc3VsdHNPdXRJbXB1bHMkUnNxdWFyZWQNCg0KYGBgDQoNCmBgYHtyfQ0KDQojIHN0b3JlIHJlc3VsdHMNCnJlc2RIaUFubm95Rml0WydEaWZmIGltcHVscycsICdSTVNFJ10gPC0gcmVzdWx0c091dEltcHVscyRPT0JfUk1TRQ0KcmVzZEhpQW5ub3lGaXRbJ0RpZmYgaW1wdWxzJywgJ01BRSddIDwtIHJlc3VsdHNPdXRJbXB1bHMkT09CX01BRQ0KcmVzZEhpQW5ub3lGaXRbJ0RpZmYgaW1wdWxzJywgJ1JzcXVhcmVkJ10gPC0gcmVzdWx0c091dEltcHVscyRSc3F1YXJlZA0KcmVzZEhpQW5ub3lQZXJtSW1wJERpZmZJbXB1bHMgPC0gcmVzdWx0c091dEltcHVscyRjb25kaXRpb25hbF9wZXJtaW1wDQoNCmBgYA0KDQojIyMjIyMgUGxvdCByZXN1bHRzDQoNCmBgYHtyLCBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTJ9DQpwYXIobWFpPWMoMCwzLDAsMCkpDQoNCiMgcGxvdCBjb25kaXRpb25hbCBpbXBvcnRhbmNlDQpyZXN1bHRzT3V0SW1wdWxzLmNvbmltcCA8LSBhcnJhbmdlKHJlc3VsdHNPdXRJbXB1bHMkY29uZGl0aW9uYWxfcGVybWltcCwgZGVzYyhyb3dfbnVtYmVyKCkpKQ0KDQpwQmFyIDwtIGdncGxvdChyZXN1bHRzT3V0SW1wdWxzLmNvbmltcCkgKyBnZW9tX2NvbChhZXMoeD1mYWN0b3Iocm93bmFtZXMocmVzdWx0c091dEltcHVscy5jb25pbXApLCBsZXZlbHM9cm93bmFtZXMocmVzdWx0c091dEltcHVscy5jb25pbXApKSwgeT1Db25kUGVybUltcCksIGZpbGw9bXljb2xvdXJzWzZdLCB3aWR0aD0wLjUpICsgbGFicyh4PSJWYXJpYWJsZSIsIHk9IkNvbmRpdGlvbmFsIHZhcmlhYmxlIHBlcm11dGF0aW9uIGltcG9ydGFuY2UgKCUgaGlnaGx5IGFubm95ZWQpIikgKyBnZ3RpdGxlKCJkSW1wdWxzaXZlbmVzcyIpICsgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2VyaWYiKSwgcGFuZWwuZ3JpZD1lbGVtZW50X2xpbmUoY29sb3IgPSByZ2IoMjM1LCAyMzUsIDIzNSwgMTAwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgbGluZXdpZHRoID0gMC4yNSwgbGluZXR5cGUgPSAyKSkgKyBjb29yZF9mbGlwKCkNCnBCYXINCg0KaWYgKHNhdmVwbG90cyl7DQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBZEhpQW5ub3lkSW1wdWxzQ29uUGVybWltcC5zdmciLCB3aWR0aD04LCBoZWlnaHQ9MiwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInN2ZyIpKQ0KICB1bmxpbmsoIlB0QWRIaUFubm95ZEltcHVsc0NvblBlcm1pbXAuc3ZnIikNCiAgDQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBZEhpQW5ub3lkSW1wdWxzQ29uUGVybWltcC5wZGYiLCB3aWR0aD04LCBoZWlnaHQ9MiwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInBkZiIpKQ0KICB1bmxpbmsoIlB0QWRIaUFubm95ZEltcHVsc0NvblBlcm1pbXAucGRmIikNCn0NCg0KYGBgDQoNClNlbGVjdGVkIG1ldHJpYw0KDQpgYGB7cn0NCg0KZEltcHVsc1ZhciA8LSAiZEltcHVsc1NITUF2Z01heExSIg0KDQpgYGANCg0KIyMjIyBkU1FNIGFuZCBsb3VkbmVzcyBjb21wYXJpc29uDQoNCk5vdyB0aGUgaGlnaGVzdCBpbXBvcnRhbmNlIGRTUU1zIGFyZSByYW5rZWQgYWdhaW5zdCBlYWNoIG90aGVyLCBjb250cm9sbGluZyBmb3IgbG91ZG5lc3MgZGlmZmVyZW5jZS4NCg0KIyMjIyMgSW5jbHVkZSBkdG9uYWwgbG91ZG5lc3MNCg0KIyMjIyMjIFNldCB2YXJpYWJsZXMNCg0KYGBge3J9DQoNCmlWYXJzIDwtIGMoZGlmZlZhciwgZFNoYXJwVmFyLCBkVG9uTGRWYXIsIGRGbHVjdFZhciwgZFJvdWdoVmFyLCBkSW1wdWxzVmFyKQ0KZFZhciA8LSAiZEhpZ2hBbm5veVBjIg0KDQpzZWVkcyA8LSBjKDk4NDY1LCA1NDE2MywgNjU0MSwgMzY0ODUsIDg0OTY3NSkNCg0KYGBgDQoNCiMjIyMjIyBIeXBlcnBhcmFtZXRlciB0dW5pbmcNCg0KYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD00fQ0KDQpwIDwtIG10cnlUdW5lKGRhdGFJbj1zdGltRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWQ9c2VlZHNbMV0sDQogICAgICAgICAgICAgbnRyZWVzPW50cmVlcywgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQpwDQoNCmBgYA0KDQpTZWxlY3RlZCBoeXBlcnBhcmFtZXRlcnMNCg0KYGBge3J9DQoNCm50cmVlIDwtIDI1MDENCm10cnkgPC0gYXMuaW50ZWdlcihsZW5ndGgoaVZhcnMpLzEuNzUpDQoNCmBgYA0KDQoNCiMjIyMjIyBSdW4gbW9kZWwNCg0KVHJhaW4gcHJlbGltaW5hcnkgbW9kZWwNCg0KYGBge3J9DQoNCm5wZXJtIDwtIDUNCg0KcmVzdWx0c091dFNRTXMxIDwtIGNyZlJlZyhkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkc1sxOjJdLCBudHJlZT1udHJlZSwgbXRyeT1tdHJ5LCBwZXJtSW1wQ29uZFRocmVzPXBlcm1JbXBDb25kVGhyZXMsIG5wZXJtPW5wZXJtLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCg0KIyBwcmludCBtb2RlbCBwcmVkaWN0aW9uIHJlc3VsdHMNCnJlc3VsdHNPdXRTUU1zMSRPT0JfUk1TRQ0KcmVzdWx0c091dFNRTXMxJE9PQl9NQUUNCnJlc3VsdHNPdXRTUU1zMSRSc3F1YXJlZA0KDQpgYGANCg0KVHJhaW4gbXVsdGlwbGUgc2VlZHMgbW9kZWwNCg0KYGBge3J9DQoNCnJlc3VsdHNPdXRTUU1zMSA8LSBtdWx0aV9jcmZSZWcoZGF0YUluPXN0aW1EYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHMsIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dFNRTXMxJE9PQl9STVNFDQpyZXN1bHRzT3V0U1FNczEkT09CX01BRQ0KcmVzdWx0c091dFNRTXMxJFJzcXVhcmVkDQoNCmBgYA0KDQpgYGB7cn0NCg0KIyBzdG9yZSByZXN1bHRzDQpyZXNkSGlBbm5veUZpdFsnRGlmZiBTUU1zIGluYyB0b25hbCBsb3VkJywgJ1JNU0UnXSA8LSByZXN1bHRzT3V0U1FNczEkT09CX1JNU0UNCnJlc2RIaUFubm95Rml0WydEaWZmIFNRTXMgaW5jIHRvbmFsIGxvdWQnLCAnTUFFJ10gPC0gcmVzdWx0c091dFNRTXMxJE9PQl9NQUUNCnJlc2RIaUFubm95Rml0WydEaWZmIFNRTXMgaW5jIHRvbmFsIGxvdWQnLCAnUnNxdWFyZWQnXSA8LSByZXN1bHRzT3V0U1FNczEkUnNxdWFyZWQNCnJlc2RIaUFubm95UGVybUltcCREaWZmU1FNczEgPC0gcmVzdWx0c091dFNRTXMxJGNvbmRpdGlvbmFsX3Blcm1pbXANCg0KYGBgDQoNCiMjIyMjIyBQbG90IHJlc3VsdHMNCg0KYGBge3IsIGZpZy53aWR0aD04LGZpZy5oZWlnaHQ9Mi40fQ0KcGFyKG1haT1jKDAsMywwLDApKQ0KDQojIHBsb3QgY29uZGl0aW9uYWwgaW1wb3J0YW5jZQ0KcmVzdWx0c091dFNRTXMxLmNvbmltcCA8LSBhcnJhbmdlKHJlc3VsdHNPdXRTUU1zMSRjb25kaXRpb25hbF9wZXJtaW1wLCBkZXNjKHJvd19udW1iZXIoKSkpDQoNCnBCYXIgPC0gZ2dwbG90KHJlc3VsdHNPdXRTUU1zMS5jb25pbXApICsgZ2VvbV9jb2woYWVzKHg9ZmFjdG9yKHJvd25hbWVzKHJlc3VsdHNPdXRTUU1zMS5jb25pbXApLCBsZXZlbHM9cm93bmFtZXMocmVzdWx0c091dFNRTXMxLmNvbmltcCkpLCB5PUNvbmRQZXJtSW1wKSwgZmlsbD1teWNvbG91cnNbN10sIHdpZHRoPTAuNSkgKyBsYWJzKHg9IlZhcmlhYmxlIiwgeT0iQ29uZGl0aW9uYWwgdmFyaWFibGUgcGVybXV0YXRpb24gaW1wb3J0YW5jZSAoJSBoaWdobHkgYW5ub3llZCkiKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiksIHBhbmVsLmdyaWQ9ZWxlbWVudF9saW5lKGNvbG9yID0gcmdiKDIzNSwgMjM1LCAyMzUsIDEwMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksIGxpbmV3aWR0aCA9IDAuMjUsIGxpbmV0eXBlID0gMikpICsgY29vcmRfZmxpcCh5bGltPWMoMCwgNTApKQ0KcEJhcg0KDQppZiAoc2F2ZXBsb3RzKXsNCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFkSGlBbm5veURpZmZTUU1zVG9uTGRDb25QZXJtaW1wLnN2ZyIsIHdpZHRoPTgsIGhlaWdodD0yLjQsIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJzdmciKSkNCiAgdW5saW5rKCJQdEFkSGlBbm5veURpZmZTUU1zVG9uTGRDb25QZXJtaW1wLnN2ZyIpDQogIA0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWRIaUFubm95RGlmZlNRTXNUb25MZENvblBlcm1pbXAucGRmIiwgd2lkdGg9OCwgaGVpZ2h0PTIuNCwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInBkZiIpKQ0KICB1bmxpbmsoIlB0QWRIaUFubm95RGlmZlNRTXNUb25MZENvblBlcm1pbXAucGRmIikNCn0NCg0KYGBgDQoNCiMjIyMjIEV4Y2x1ZGUgdG9uYWwgbG91ZG5lc3MNCg0KIyMjIyMjIFNldCB2YXJpYWJsZXMNCg0KYGBge3J9DQoNCmlWYXJzIDwtIGMoZGlmZlZhciwgZFNoYXJwVmFyLCBkVG9uYWxWYXIsIGRGbHVjdFZhciwgZFJvdWdoVmFyLCBkSW1wdWxzVmFyKQ0KZFZhciA8LSAiZEhpZ2hBbm5veVBjIg0KDQpzZWVkcyA8LSBjKDQ5ODY1LCA3ODUyLCA4NDU5NjEsIDQxMDU4MywgMzY3NDgpDQoNCmBgYA0KDQojIyMjIyMgSHlwZXJwYXJhbWV0ZXIgdHVuaW5nDQoNCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NH0NCg0KcCA8LSBtdHJ5VHVuZShkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkPXNlZWRzWzFdLA0KICAgICAgICAgICAgIG50cmVlcz1udHJlZXMsIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KcA0KDQpgYGANCg0KU2VsZWN0ZWQgaHlwZXJwYXJhbWV0ZXJzDQoNCmBgYHtyfQ0KDQpudHJlZSA8LSA0MDAxDQptdHJ5IDwtIGFzLmludGVnZXIobGVuZ3RoKGlWYXJzKS8xLjc1KQ0KDQpgYGANCg0KIyMjIyMjIFJ1biBtb2RlbA0KDQpUcmFpbiBwcmVsaW1pbmFyeSBtb2RlbA0KDQpgYGB7cn0NCg0KbnBlcm0gPC0gNQ0KDQpyZXN1bHRzT3V0U1FNczIgPC0gY3JmUmVnKGRhdGFJbj1zdGltRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzWzE6Ml0sIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dFNRTXMyJE9PQl9STVNFDQpyZXN1bHRzT3V0U1FNczIkT09CX01BRQ0KcmVzdWx0c091dFNRTXMyJFJzcXVhcmVkDQoNCmBgYA0KDQpUcmFpbiBtdWx0aXBsZSBzZWVkcyBtb2RlbA0KDQpgYGB7cn0NCg0KcmVzdWx0c091dFNRTXMyIDwtIG11bHRpX2NyZlJlZyhkYXRhSW49c3RpbURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkcywgbnRyZWU9bnRyZWUsIG10cnk9bXRyeSwgcGVybUltcENvbmRUaHJlcz1wZXJtSW1wQ29uZFRocmVzLCBucGVybT1ucGVybSwgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQoNCiMgcHJpbnQgbW9kZWwgcHJlZGljdGlvbiByZXN1bHRzDQpyZXN1bHRzT3V0U1FNczIkT09CX1JNU0UNCnJlc3VsdHNPdXRTUU1zMiRPT0JfTUFFDQpyZXN1bHRzT3V0U1FNczIkUnNxdWFyZWQNCg0KYGBgDQoNCmBgYHtyfQ0KDQojIHN0b3JlIHJlc3VsdHMNCnJlc2RIaUFubm95Rml0WydEaWZmIFNRTXMgbm8gdG9uYWwgbG91ZCcsICdSTVNFJ10gPC0gcmVzdWx0c091dFNRTXMyJE9PQl9STVNFDQpyZXNkSGlBbm5veUZpdFsnRGlmZiBTUU1zIG5vIHRvbmFsIGxvdWQnLCAnUk1TRSddIDwtIHJlc3VsdHNPdXRTUU1zMiRPT0JfTUFFDQpyZXNkSGlBbm5veUZpdFsnRGlmZiBTUU1zIG5vIHRvbmFsIGxvdWQnLCAnUnNxdWFyZWQnXSA8LSByZXN1bHRzT3V0U1FNczIkUnNxdWFyZWQNCnJlc2RIaUFubm95UGVybUltcCREaWZmU1FNczIgPC0gcmVzdWx0c091dFNRTXMyJGNvbmRpdGlvbmFsX3Blcm1pbXANCg0KYGBgDQoNCiMjIyMjIyBQbG90IHJlc3VsdHMNCg0KYGBge3IsIGZpZy53aWR0aD04LGZpZy5oZWlnaHQ9Mi40fQ0KcGFyKG1haT1jKDAsMywwLDApKQ0KDQojIHBsb3QgY29uZGl0aW9uYWwgaW1wb3J0YW5jZQ0KcmVzdWx0c091dFNRTXMyLmNvbmltcCA8LSBhcnJhbmdlKHJlc3VsdHNPdXRTUU1zMiRjb25kaXRpb25hbF9wZXJtaW1wLCBkZXNjKHJvd19udW1iZXIoKSkpDQoNCnBCYXIgPC0gZ2dwbG90KHJlc3VsdHNPdXRTUU1zMi5jb25pbXApICsgZ2VvbV9jb2woYWVzKHg9ZmFjdG9yKHJvd25hbWVzKHJlc3VsdHNPdXRTUU1zMi5jb25pbXApLCBsZXZlbHM9cm93bmFtZXMocmVzdWx0c091dFNRTXMyLmNvbmltcCkpLCB5PUNvbmRQZXJtSW1wKSwgZmlsbD1teWNvbG91cnNbN10sIHdpZHRoPTAuNSkgKyBsYWJzKHg9IlZhcmlhYmxlIiwgeT0iQ29uZGl0aW9uYWwgdmFyaWFibGUgcGVybXV0YXRpb24gaW1wb3J0YW5jZSAoJSBoaWdobHkgYW5ub3llZCkiKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiksIHBhbmVsLmdyaWQ9ZWxlbWVudF9saW5lKGNvbG9yID0gcmdiKDIzNSwgMjM1LCAyMzUsIDEwMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksIGxpbmV3aWR0aCA9IDAuMjUsIGxpbmV0eXBlID0gMikpICsgY29vcmRfZmxpcCh5bGltPWMoMCwgNTApKQ0KcEJhcg0KDQppZiAoc2F2ZXBsb3RzKXsNCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFkSGlBbm5veURpZmZTUU1zTm9Ub25MZENvblBlcm1pbXAuc3ZnIiwgd2lkdGg9OCwgaGVpZ2h0PTIuNCwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInN2ZyIpKQ0KICB1bmxpbmsoIlB0QWRIaUFubm95RGlmZlNRTXNOb1RvbkxkQ29uUGVybWltcC5zdmciKQ0KICANCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFkSGlBbm5veURpZmZTUU1zTm9Ub25MZENvblBlcm1pbXAucGRmIiwgd2lkdGg9OCwgaGVpZ2h0PTIuNCwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInBkZiIpKQ0KICB1bmxpbmsoIlB0QWRIaUFubm95RGlmZlNRTXNOb1RvbkxkQ29uUGVybWltcC5wZGYiKQ0KfQ0KDQpgYGANCg0KIyMjIFNhdmUgdGhlIHJlc3VsdHMgb3V0cHV0cyB0byBmaWxlDQoNCmBgYHtyfQ0KDQppZiAoc2F2ZWRhdGEpew0KICB1dGlsczo6d3JpdGUuY3N2KHJlc2RIaUFubm95Rml0LCBwYXN0ZShvdXREYXRhUGF0aCwgIlxccHRBQ1JGZEhpQW5ub3lPT0JGaXQuY3N2Iiwgc2VwPSIiKSkNCiAgaWkgPC0gMA0KICB0ZW1wID0gbGlzdCgpDQogIGZvciAocmVzIGluIHJlc2RIaUFubm95UGVybUltcCl7DQogICAgaWkgPC0gaWkgKyAxDQogICAgdGVtcFtbaWldXSA8LSBhcy5kYXRhLmZyYW1lKHJlc2RIaUFubm95UGVybUltcFtpaV0pDQogICAgbmFtZXModGVtcFtbaWldXSkgPC0gbmFtZXMocmVzZEhpQW5ub3lQZXJtSW1wW2lpXSkNCiAgfQ0KICBvcGVueGxzeDo6d3JpdGUueGxzeCh0ZW1wLCBwYXN0ZShvdXREYXRhUGF0aCwgIlxccHRBQ1JGZEhpQW5ub3lDb25QZXJtaW1wLnhsc3giLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXA9IiIpLA0KICAgICAgICAgICAgICAgICAgICAgICByb3dOYW1lcz1UUlVFKQ0KfQ0KDQpgYGANCg0KIyMgTm90aWNlYWJpbGl0eQ0KDQpJbml0aWFsaXNlIHJlc3VsdHMgb3V0cHV0IHZhcmlhYmxlcw0KDQpgYGB7cn0NCnJlc05vdGljZUZpdCA8LSBkYXRhLmZyYW1lKFJNU0UgPSBudW1lcmljKCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1BRSA9IG51bWVyaWMoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUnNxdWFyZWQgPSBudW1lcmljKCkpDQpyZXNOb3RpY2VQZXJtSW1wIDwtIGxpc3QoKQ0KDQpgYGANCg0KIyMjIEFsbCB2YXJpYWJsZXMgKGFic29sdXRlIGFuZCBkaWZmZXJlbmNlKQ0KDQojIyMjIFJlbW92ZSBhbWJpZW50IG9ubHkgc3RpbXVsaQ0KDQpIZXJlLCB0aGUgJ2FtYmllbnQgb25seScgc3RpbXVsaSBhcmUgcmVtb3ZlZCwgYXMgdGhlIGFuYWx5c2lzIGNhbm5vdCBoYW5kbGUgbWlzc2luZyB2YWx1ZXMgZm9yIGRCIG1ldHJpY3MuDQoNCmBgYHtyfQ0Kc3RpbU5vdGljZURhdGFBTnVtIDwtIHN0aW1Ob3RpY2VEYXRhQU51bVtjb21wbGV0ZS5jYXNlcyhzdGltTm90aWNlRGF0YUFOdW0pLF0NCnN0aW1Ob3RpY2VEYXRhQU51bSRVQVNMQWVxIDwtIGFzLm51bWVyaWMoc3RpbU5vdGljZURhdGFBTnVtJFVBU0xBZXEpDQpzdGltTm90aWNlRGF0YUFOdW0kU05SbGV2ZWwgPC0gYXMubnVtZXJpYyhzdGltTm90aWNlRGF0YUFOdW0kU05SbGV2ZWwpDQpgYGANCg0KIyMjIyBTZXQgdmFyaWFibGVzDQoNCmBgYHtyfQ0KDQppVmFycyA8LSBuYW1lcyhzdGltTm90aWNlRGF0YUFOdW0pW3doaWNoKG5hbWVzKHN0aW1Ob3RpY2VEYXRhQU51bSkgPT0gJ1VBU0xBZXEnKTp3aGljaChuYW1lcyhzdGltTm90aWNlRGF0YUFOdW0pID09ICdVQVNJbXB1bHNTSE0wNUV4TWF4TFInKV0NCmlWYXJzIDwtIGlWYXJzWyEgaVZhcnMgJWluJSAnU05SbGV2ZWwnXQ0KaVZhcnMgPC0gYyhpVmFycywNCiAgICAgICAgICAgbmFtZXMoc3RpbU5vdGljZURhdGFBTnVtKVt3aGljaChjb2xuYW1lcyhzdGltTm90aWNlRGF0YUFOdW0pPT0iTEFlcUxBRjkwZGlmZiIpOg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoKGNvbG5hbWVzKHN0aW1Ob3RpY2VEYXRhQU51bSk9PSJkSW1wdWxzU0hNMDVFeE1heExSIildLCAiU05SbGV2ZWwiKQ0KZFZhciA8LSAiTm90aWNlZFBjRmlsdCINCg0Kc2VlZHMgPC0gYygyLCAzMTIsIDE4OTcsIDQ2NTk3OCwgODIxNjU5KQ0KDQpgYGANCg0KIyMjIyBIeXBlcnBhcmFtZXRlciB0dW5pbmcNCg0KYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD00fQ0KDQpwIDwtIG10cnlUdW5lKGRhdGFJbj1zdGltTm90aWNlRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWQ9c2VlZHNbMV0sDQogICAgICAgICAgICAgbnRyZWVzPW50cmVlcywgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQpwDQoNCmBgYA0KDQpTZWxlY3RlZCBoeXBlcnBhcmFtZXRlcnMNCg0KYGBge3J9DQoNCm50cmVlIDwtIDE1MDENCm10cnkgPC0gYXMuaW50ZWdlcihsZW5ndGgoaVZhcnMpLzIuNzUpDQoNCmBgYA0KDQojIyMjIFJ1biBtb2RlbA0KDQpUcmFpbiBwcmVsaW1pbmFyeSBtb2RlbA0KDQpgYGB7cn0NCg0KbnBlcm0gPC0gMTANCg0KcmVzdWx0c091dEFic0RpZmZzIDwtIGNyZlJlZyhkYXRhSW49c3RpbU5vdGljZURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkc1sxOjJdLCBudHJlZT1udHJlZSwgbXRyeT1tdHJ5LCBwZXJtSW1wQ29uZFRocmVzPXBlcm1JbXBDb25kVGhyZXMsIG5wZXJtPW5wZXJtLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCg0KIyBwcmludCBtb2RlbCBwcmVkaWN0aW9uIHJlc3VsdHMNCnJlc3VsdHNPdXRBYnNEaWZmcyRPT0JfUk1TRQ0KcmVzdWx0c091dEFic0RpZmZzJE9PQl9NQUUNCnJlc3VsdHNPdXRBYnNEaWZmcyRSc3F1YXJlZA0KDQpgYGANCg0KVHJhaW4gbXVsdGlwbGUgc2VlZHMgbW9kZWwNCg0KYGBge3J9DQoNCnJlc3VsdHNPdXRBYnNEaWZmcyA8LSBtdWx0aV9jcmZSZWcoZGF0YUluPXN0aW1Ob3RpY2VEYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHMsIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dEFic0RpZmZzJE9PQl9STVNFDQpyZXN1bHRzT3V0QWJzRGlmZnMkT09CX01BRQ0KcmVzdWx0c091dEFic0RpZmZzJFJzcXVhcmVkDQpgYGANCg0KYGBge3J9DQojIHN0b3JlIHJlc3VsdHMNCnJlc05vdGljZUZpdFsnQWxsIHZhcnMnLCAnUk1TRSddIDwtIHJlc3VsdHNPdXRBYnNEaWZmcyRPT0JfUk1TRQ0KcmVzTm90aWNlRml0WydBbGwgdmFycycsICdNQUUnXSA8LSByZXN1bHRzT3V0QWJzRGlmZnMkT09CX01BRQ0KcmVzTm90aWNlRml0WydBbGwgdmFycycsICdSc3F1YXJlZCddIDwtIHJlc3VsdHNPdXRBYnNEaWZmcyRSc3F1YXJlZA0KcmVzTm90aWNlUGVybUltcCRBbGxWYXJzIDwtIHJlc3VsdHNPdXRBYnNEaWZmcyRjb25kaXRpb25hbF9wZXJtaW1wDQoNCmBgYA0KDQojIyMjIFBsb3QgcmVzdWx0cw0KDQpgYGB7ciwgZmlnLndpZHRoPTgsZmlnLmhlaWdodD0yMH0NCnBhcihtYWk9YygwLDMsMCwwKSkNCg0KIyBwbG90IGNvbmRpdGlvbmFsIGltcG9ydGFuY2UNCnJlc3VsdHNPdXRBYnNEaWZmcy5jb25pbXAgPC0gYXJyYW5nZShyZXN1bHRzT3V0QWJzRGlmZnMkY29uZGl0aW9uYWxfcGVybWltcCwgZGVzYyhyb3dfbnVtYmVyKCkpKQ0KDQpwQmFyIDwtIGdncGxvdChyZXN1bHRzT3V0QWJzRGlmZnMuY29uaW1wKSArIGdlb21fY29sKGFlcyh4PWZhY3Rvcihyb3duYW1lcyhyZXN1bHRzT3V0QWJzRGlmZnMuY29uaW1wKSwgbGV2ZWxzPXJvd25hbWVzKHJlc3VsdHNPdXRBYnNEaWZmcy5jb25pbXApKSwgeT1Db25kUGVybUltcCksIGZpbGw9bXljb2xvdXJzWzldLCB3aWR0aD0wLjUpICsgbGFicyh4PSJWYXJpYWJsZSIsIHk9IkNvbmRpdGlvbmFsIHZhcmlhYmxlIHBlcm11dGF0aW9uIGltcG9ydGFuY2UgKCUgVUFTIG5vdGljZWQpIikgKyB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIpLCBwYW5lbC5ncmlkPWVsZW1lbnRfbGluZShjb2xvciA9IHJnYigyMzUsIDIzNSwgMjM1LCAxMDAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCBsaW5ld2lkdGggPSAwLjI1LCBsaW5ldHlwZSA9IDIpKSArIGNvb3JkX2ZsaXAoKQ0KcEJhcg0KDQppZiAoc2F2ZXBsb3RzKXsNCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFOb3RpY2VBbGxWYXJzQ29uUGVybWltcC5zdmciLCB3aWR0aD04LCBoZWlnaHQ9MjAsIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJzdmciKSkNCiAgdW5saW5rKCJQdEFOb3RpY2VBbGxWYXJzQ29uUGVybWltcC5zdmciKQ0KDQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBTm90aWNlQWxsVmFyc0NvblBlcm1pbXAucGRmIiwgd2lkdGg9OCwgaGVpZ2h0PTIwLCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAicGRmIikpDQogIHVubGluaygiUHRBTm90aWNlQWxsVmFyc0NvblBlcm1pbXAucGRmIikNCn0NCg0KYGBgDQoNCmBgYHtyLCBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTEyfQ0KDQojIFBsb3Qgb25seSBwb3NpdGl2ZSB2YWx1ZXMNCg0KcmVzdWx0c091dEFic0RpZmZzLmNvbmltcFB0diA8LSByZXN1bHRzT3V0QWJzRGlmZnMuY29uaW1wIHw+DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3duYW1lc190b19jb2x1bW4oJ01ldHJpYycpIHw+DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXJfaWYoaXMubnVtZXJpYywgYWxsX3ZhcnMoLiA+IDApKSB8Pg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sdW1uX3RvX3Jvd25hbWVzKCdNZXRyaWMnKQ0KDQpwQmFyIDwtIGdncGxvdChyZXN1bHRzT3V0QWJzRGlmZnMuY29uaW1wUHR2KSArIGdlb21fY29sKGFlcyh4PWZhY3Rvcihyb3duYW1lcyhyZXN1bHRzT3V0QWJzRGlmZnMuY29uaW1wUHR2KSwgbGV2ZWxzPXJvd25hbWVzKHJlc3VsdHNPdXRBYnNEaWZmcy5jb25pbXBQdHYpKSwgeT1Db25kUGVybUltcCksIGZpbGw9bXljb2xvdXJzWzldLCB3aWR0aD0wLjUpICsgbGFicyh4PSJWYXJpYWJsZSIsIHk9IkNvbmRpdGlvbmFsIHZhcmlhYmxlIHBlcm11dGF0aW9uIGltcG9ydGFuY2UgKCUgVUFTIG5vdGljZWQpIikgKyB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIpLCBwYW5lbC5ncmlkPWVsZW1lbnRfbGluZShjb2xvciA9IHJnYigyMzUsIDIzNSwgMjM1LCAxMDAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCBsaW5ld2lkdGggPSAwLjI1LCBsaW5ldHlwZSA9IDIpKSArIGNvb3JkX2ZsaXAoKQ0KcEJhcg0KDQppZiAoc2F2ZXBsb3RzKXsNCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFOb3RpY2VBbGxWYXJzQ29uUGVybWltcFB0di5zdmciLCB3aWR0aD04LCBoZWlnaHQ9MTIsIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJzdmciKSkNCiAgdW5saW5rKCJQdEFOb3RpY2VBbGxWYXJzQ29uUGVybWltcC5zdmciKQ0KICANCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFOb3RpY2VBbGxWYXJzQ29uUGVybWltcFB0di5wZGYiLCB3aWR0aD04LCBoZWlnaHQ9MTIsIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJwZGYiKSkNCiAgdW5saW5rKCJQdEFOb3RpY2VBbGxWYXJzQ29uUGVybWltcC5wZGYiKQ0KfQ0KDQpgYGANCg0KIyMjIEFic29sdXRlIHZhcmlhYmxlcw0KDQojIyMjIFNldCB2YXJpYWJsZXMNCg0KYGBge3J9DQoNCmlWYXJzIDwtIG5hbWVzKHN0aW1Ob3RpY2VEYXRhQU51bSlbd2hpY2gobmFtZXMoc3RpbU5vdGljZURhdGFBTnVtKSA9PSAnVUFTTEFlcScpOndoaWNoKG5hbWVzKHN0aW1Ob3RpY2VEYXRhQU51bSkgPT0gJ1VBU0ltcHVsc1NITTA1RXhNYXhMUicpXQ0KaVZhcnMgPC0gaVZhcnNbISBpVmFycyAlaW4lIGMoJ1NOUmxldmVsJyldDQpkVmFyIDwtICJOb3RpY2VkUGNGaWx0Ig0KDQpzZWVkcyA8LSBjKDU3ODMxMiwgNTQ0LCA4NDg5NCwgNTQ2NTQsIDE1MzE1NykNCg0KYGBgDQoNCiMjIyMgSHlwZXJwYXJhbWV0ZXIgdHVuaW5nDQoNCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NH0NCg0KcCA8LSBtdHJ5VHVuZShkYXRhSW49c3RpbU5vdGljZURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkPXNlZWRzWzFdLA0KICAgICAgICAgICAgIG50cmVlcz1udHJlZXMsIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KcA0KDQppZiAoc2F2ZXBsb3RzKXsNCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFOb3RpY2VBYnNWYXJzSHlwZXJUdW5lLnN2ZyIsIHdpZHRoPTEyLCBoZWlnaHQ9NCwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInN2ZyIpKQ0KICB1bmxpbmsoIlB0QU5vdGljZUFic1ZhcnNIeXBlclR1bmUuc3ZnIikNCg0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QU5vdGljZUFic1ZhcnNIeXBlclR1bmUucGRmIiwgd2lkdGg9MTIsIGhlaWdodD00LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAicGRmIikpDQogIHVubGluaygiUHRBTm90aWNlQWJzVmFyc0h5cGVyVHVuZS5wZGYiKQ0KfQ0KDQpgYGANCg0KU2VsZWN0ZWQgaHlwZXJwYXJhbWV0ZXJzDQoNCmBgYHtyfQ0KDQpudHJlZSA8LSAyNTAxDQptdHJ5IDwtIGFzLmludGVnZXIobGVuZ3RoKGlWYXJzKS8xLjI1KQ0KDQpgYGANCg0KIyMjIyBSdW4gbW9kZWwNCg0KVHJhaW4gcHJlbGltaW5hcnkgbW9kZWwNCg0KYGBge3J9DQoNCm5wZXJtIDwtIDIwDQoNCnJlc3VsdHNPdXRBYnMgPC0gY3JmUmVnKGRhdGFJbj1zdGltTm90aWNlRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzWzE6Ml0sIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dEFicyRPT0JfUk1TRQ0KcmVzdWx0c091dEFicyRPT0JfTUFFDQpyZXN1bHRzT3V0QWJzJFJzcXVhcmVkDQoNCmBgYA0KVHJhaW4gbXVsdGlwbGUgc2VlZHMgbW9kZWwNCg0KYGBge3J9DQoNCnJlc3VsdHNPdXRBYnMgPC0gbXVsdGlfY3JmUmVnKGRhdGFJbj1zdGltTm90aWNlRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzLCBudHJlZT1udHJlZSwgbXRyeT1tdHJ5LCBwZXJtSW1wQ29uZFRocmVzPXBlcm1JbXBDb25kVGhyZXMsIG5wZXJtPW5wZXJtLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCg0KIyBwcmludCBtb2RlbCBwcmVkaWN0aW9uIHJlc3VsdHMNCnJlc3VsdHNPdXRBYnMkT09CX1JNU0UNCnJlc3VsdHNPdXRBYnMkT09CX01BRQ0KcmVzdWx0c091dEFicyRSc3F1YXJlZA0KDQpgYGANCg0KDQpgYGB7cn0NCg0KIyBzdG9yZSByZXN1bHRzDQpyZXNOb3RpY2VGaXRbJ0FicyB2YXJzJywgJ1JNU0UnXSA8LSByZXN1bHRzT3V0QWJzJE9PQl9STVNFDQpyZXNOb3RpY2VGaXRbJ0FicyB2YXJzJywgJ01BRSddIDwtIHJlc3VsdHNPdXRBYnMkT09CX01BRQ0KcmVzTm90aWNlRml0WydBYnMgdmFycycsICdSc3F1YXJlZCddIDwtIHJlc3VsdHNPdXRBYnMkUnNxdWFyZWQNCnJlc05vdGljZVBlcm1JbXAkQWJzVmFycyA8LSByZXN1bHRzT3V0QWJzJGNvbmRpdGlvbmFsX3Blcm1pbXANCg0KYGBgDQoNCiMjIyMgUGxvdCByZXN1bHRzDQoNCmBgYHtyLCBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTExLjV9DQpwYXIobWFpPWMoMCwzLDAsMCkpDQoNCiMgcGxvdCBjb25kaXRpb25hbCBpbXBvcnRhbmNlDQpyZXN1bHRzT3V0QWJzLmNvbmltcCA8LSBhcnJhbmdlKHJlc3VsdHNPdXRBYnMkY29uZGl0aW9uYWxfcGVybWltcCwgZGVzYyhyb3dfbnVtYmVyKCkpKQ0KDQpwQmFyIDwtIGdncGxvdChyZXN1bHRzT3V0QWJzLmNvbmltcCkgKyBnZW9tX2NvbChhZXMoeD1mYWN0b3Iocm93bmFtZXMocmVzdWx0c091dEFicy5jb25pbXApLCBsZXZlbHM9cm93bmFtZXMocmVzdWx0c091dEFicy5jb25pbXApKSwgeT1Db25kUGVybUltcCksIGZpbGw9bXljb2xvdXJzWzFdLCB3aWR0aD0wLjUpICsgbGFicyh4PSJWYXJpYWJsZSIsIHk9IkNvbmRpdGlvbmFsIHZhcmlhYmxlIHBlcm11dGF0aW9uIGltcG9ydGFuY2UgKCUgVUFTIG5vdGljZWQpIikgKyB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIpLCBwYW5lbC5ncmlkPWVsZW1lbnRfbGluZShjb2xvciA9IHJnYigyMzUsIDIzNSwgMjM1LCAxMDAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCBsaW5ld2lkdGggPSAwLjI1LCBsaW5ldHlwZSA9IDIpKSArDQogIGNvb3JkX2ZsaXAoKQ0KcEJhcg0KDQppZiAoc2F2ZXBsb3RzKXsNCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFOb3RpY2VBYnNWYXJzQ29uUGVybWltcC5zdmciLCB3aWR0aD04LCBoZWlnaHQ9MTEuNSwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInN2ZyIpKQ0KICB1bmxpbmsoIlB0QU5vdGljZUFic1ZhcnNDb25QZXJtaW1wLnN2ZyIpDQogIA0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QU5vdGljZUFic1ZhcnNDb25QZXJtaW1wLnBkZiIsIHdpZHRoPTgsIGhlaWdodD0xMS41LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAicGRmIikpDQogIHVubGluaygiUHRBTm90aWNlQWJzVmFyc0NvblBlcm1pbXAucGRmIikNCn0NCmBgYA0KDQoNCmBgYHtyLCBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTd9DQoNCiMgUGxvdCBvbmx5IHBvc2l0aXZlIHZhbHVlcw0KcmVzdWx0c091dEFicy5jb25pbXBQdHYgPC0gcmVzdWx0c091dEFicy5jb25pbXAgfD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvd25hbWVzX3RvX2NvbHVtbignTWV0cmljJykgfD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcl9pZihpcy5udW1lcmljLCBhbGxfdmFycyguID4gMCkpIHw+DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2x1bW5fdG9fcm93bmFtZXMoJ01ldHJpYycpDQoNCnBCYXIgPC0gZ2dwbG90KHJlc3VsdHNPdXRBYnMuY29uaW1wUHR2LCkgKyBnZW9tX2NvbChhZXMoeD1mYWN0b3Iocm93bmFtZXMocmVzdWx0c091dEFicy5jb25pbXBQdHYpLCBsZXZlbHM9cm93bmFtZXMocmVzdWx0c091dEFicy5jb25pbXBQdHYpKSwgeT1Db25kUGVybUltcCksIGZpbGw9bXljb2xvdXJzWzFdLCB3aWR0aD0wLjUpICsgbGFicyh4PSJWYXJpYWJsZSIsIHk9IkNvbmRpdGlvbmFsIHZhcmlhYmxlIHBlcm11dGF0aW9uIGltcG9ydGFuY2UgKCUgVUFTIG5vdGljZWQpIikgKyB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIpLCBwYW5lbC5ncmlkPWVsZW1lbnRfbGluZShjb2xvciA9IHJnYigyMzUsIDIzNSwgMjM1LCAxMDAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCBsaW5ld2lkdGggPSAwLjI1LCBsaW5ldHlwZSA9IDIpKSArIGNvb3JkX2ZsaXAoKQ0KcEJhcg0KDQppZiAoc2F2ZXBsb3RzKXsNCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFOb3RpY2VBYnNWYXJzQ29uUGVybWltcFB0di5zdmciLCB3aWR0aD04LCBoZWlnaHQ9NywgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInN2ZyIpKQ0KICB1bmxpbmsoIlB0QU5vdGljZUFic1ZhcnNDb25QZXJtaW1wUHR2LnN2ZyIpDQogIA0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QU5vdGljZUFic1ZhcnNDb25QZXJtaW1wUHR2LnBkZiIsIHdpZHRoPTgsIGhlaWdodD03LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAicGRmIikpDQogIHVubGluaygiUHRBTm90aWNlQWJzVmFyc0NvblBlcm1pbXBQdHYucGRmIikNCn0NCg0KYGBgDQoNClNlbGVjdGVkIG1ldHJpYw0KDQpgYGB7cn0NCg0KYWJzVmFyIDwtICJVQVNQTkxtYXhNYXhMUiINCg0KYGBgDQoNCiMjIyBTUU0gYW5hbHlzaXMNCg0KIyMjIyBSZXBsYWNlIGFtYmllbnQgb25seSBzdGltdWxpDQoNCkhlcmUsIHRoZSAnYW1iaWVudCBvbmx5JyBzdGltdWxpIGFyZSBub3QgcmVwbGFjZWQsIGFzIHRoZSBhbmFseXNpcyBjYW5ub3QgaGFuZGxlIG1pc3NpbmcgdmFsdWVzIGZvciBkQiBtZXRyaWNzIChQTkwpLg0KDQpgYGB7cn0NCiMgDQojIHN0aW1Ob3RpY2VEYXRhQU51bSA8LSByYmluZChzdGltTm90aWNlRGF0YUFOdW0sIHN0aW1Ob3RpY2VEYXRhQVtzdGltTm90aWNlRGF0YUFbJ1N0aW11bHVzJ10NCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID09ICJBMSIsDQojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xuYW1lcyhzdGltTm90aWNlRGF0YUFOdW0pXSwNCiMgICAgICAgICAgICAgICAgICAgICAgIHN0aW1Ob3RpY2VEYXRhQVtzdGltTm90aWNlRGF0YUFbJ1N0aW11bHVzJ10NCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID09ICJBMiIsDQojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xuYW1lcyhzdGltTm90aWNlRGF0YUFOdW0pXSkNCiMgc3RpbU5vdGljZURhdGFBTnVtIDwtIGFycmFuZ2Uoc3RpbU5vdGljZURhdGFBTnVtLCBTdGltdWx1cykNCg0KYGBgDQoNCiMjIyMgSW5kaXZpZHVhbCBTUU1zDQoNCiMjIyMjIFNoYXJwbmVzcw0KDQojIyMjIyMgU2V0IHZhcmlhYmxlcw0KDQpgYGB7cn0NCg0KaVZhcnMgPC0gYyhhYnNWYXIsICJBbWJpZW50TEFlcSIsICJVQVNTaGFycEF1cklTTzNQb3dBdmdNYXhMUiIsICJVQVNTaGFycEF1cklTTzMwNUV4TWF4TFIiLCAiVUFTU2hhcnBBdXJTSE1Qb3dBdmdNYXhMUiIsICJVQVNTaGFycEF1clNITTA1RXhNYXhMUiIsICJVQVNTaGFycEF1cklTTzFQb3dBdmdNYXhMUiIsICJVQVNTaGFycEF1cklTTzEwNUV4TWF4TFIiLCAiVUFTU2hhcnB2QklTTzFQb3dBdmdNYXhMUiIsICJVQVNTaGFycHZCSVNPMTA1RXhNYXhMUiIsICJVQVNTaGFycERJTlBvd0F2Z01heExSIiwgIlVBU1NoYXJwRElOMDVFeE1heExSIikNCmRWYXIgPC0gIk5vdGljZWRQY0ZpbHQiDQoNCnNlZWRzIDwtIGMoNzA0MSwgOTA1LCA0OTg0NjUxLCA2NTEzMjEzLCAxMjA2NTEpDQoNCmBgYA0KDQojIyMjIyMgSHlwZXJwYXJhbWV0ZXIgdHVuaW5nDQoNCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NH0NCg0KcCA8LSBtdHJ5VHVuZShkYXRhSW49c3RpbU5vdGljZURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkPXNlZWRzWzFdLA0KICAgICAgICAgICAgIG50cmVlcz1udHJlZXMsIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KcA0KDQpgYGANCg0KU2VsZWN0ZWQgaHlwZXJwYXJhbWV0ZXJzDQoNCmBgYHtyfQ0KDQpudHJlZSA8LSAyNTAxDQptdHJ5IDwtIGFzLmludGVnZXIobGVuZ3RoKGlWYXJzKS8xLjI1KQ0KDQpgYGANCg0KDQojIyMjIyMgUnVuIG1vZGVsDQoNClRyYWluIHByZWxpbWluYXJ5IG1vZGVsDQoNCmBgYHtyfQ0KDQpucGVybSA8LSA1DQoNCnJlc3VsdHNPdXRTaGFycCA8LSBjcmZSZWcoZGF0YUluPXN0aW1Ob3RpY2VEYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHNbMToyXSwgbnRyZWU9bnRyZWUsIG10cnk9bXRyeSwgcGVybUltcENvbmRUaHJlcz1wZXJtSW1wQ29uZFRocmVzLCBucGVybT1ucGVybSwgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQogIA0KIyBwcmludCBtb2RlbCBwcmVkaWN0aW9uIHJlc3VsdHMNCnJlc3VsdHNPdXRTaGFycCRPT0JfUk1TRQ0KcmVzdWx0c091dFNoYXJwJE9PQl9NQUUNCnJlc3VsdHNPdXRTaGFycCRSc3F1YXJlZA0KDQpgYGANClRyYWluIG11bHRpcGxlIHNlZWRzIG1vZGVsDQoNCmBgYHtyfQ0KDQpyZXN1bHRzT3V0U2hhcnAgPC0gbXVsdGlfY3JmUmVnKGRhdGFJbj1zdGltTm90aWNlRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzLCBudHJlZT1udHJlZSwgbXRyeT1tdHJ5LCBwZXJtSW1wQ29uZFRocmVzPXBlcm1JbXBDb25kVGhyZXMsIG5wZXJtPW5wZXJtLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCg0KIyBwcmludCBtb2RlbCBwcmVkaWN0aW9uIHJlc3VsdHMNCnJlc3VsdHNPdXRTaGFycCRPT0JfUk1TRQ0KcmVzdWx0c091dFNoYXJwJE9PQl9NQUUNCnJlc3VsdHNPdXRTaGFycCRSc3F1YXJlZA0KDQpgYGANCg0KDQpgYGB7cn0NCiMgc3RvcmUgcmVzdWx0cw0KcmVzTm90aWNlRml0WydBYnMgc2hhcnAnLCAnUk1TRSddIDwtIHJlc3VsdHNPdXRTaGFycCRPT0JfUk1TRQ0KcmVzTm90aWNlRml0WydBYnMgc2hhcnAnLCAnTUFFJ10gPC0gcmVzdWx0c091dFNoYXJwJE9PQl9NQUUNCnJlc05vdGljZUZpdFsnQWJzIHNoYXJwJywgJ1JzcXVhcmVkJ10gPC0gcmVzdWx0c091dFNoYXJwJFJzcXVhcmVkDQpyZXNOb3RpY2VQZXJtSW1wJEFic1NoYXJwIDwtIHJlc3VsdHNPdXRTaGFycCRjb25kaXRpb25hbF9wZXJtaW1wDQoNCmBgYA0KDQojIyMjIyMgUGxvdCByZXN1bHRzDQoNCmBgYHtyLCBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTQuOX0NCnBhcihtYWk9YygwLDMsMCwwKSkNCg0KIyBwbG90IGNvbmRpdGlvbmFsIGltcG9ydGFuY2UNCnJlc3VsdHNPdXRTaGFycC5jb25pbXAgPC0gYXJyYW5nZShyZXN1bHRzT3V0U2hhcnAkY29uZGl0aW9uYWxfcGVybWltcCwgZGVzYyhyb3dfbnVtYmVyKCkpKQ0KDQpwQmFyIDwtIGdncGxvdChyZXN1bHRzT3V0U2hhcnAuY29uaW1wKSArIGdlb21fY29sKGFlcyh4PWZhY3Rvcihyb3duYW1lcyhyZXN1bHRzT3V0U2hhcnAuY29uaW1wKSwgbGV2ZWxzPXJvd25hbWVzKHJlc3VsdHNPdXRTaGFycC5jb25pbXApKSwgeT1Db25kUGVybUltcCksIGZpbGw9bXljb2xvdXJzWzJdLCB3aWR0aD0wLjUpICsgbGFicyh4PSJWYXJpYWJsZSIsIHk9IkNvbmRpdGlvbmFsIHZhcmlhYmxlIHBlcm11dGF0aW9uIGltcG9ydGFuY2UgKCUgVUFTIG5vdGljZWQpIikgKyBnZ3RpdGxlKCJTaGFycG5lc3MiKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiksIHBhbmVsLmdyaWQ9ZWxlbWVudF9saW5lKGNvbG9yID0gcmdiKDIzNSwgMjM1LCAyMzUsIDEwMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksIGxpbmV3aWR0aCA9IDAuMjUsIGxpbmV0eXBlID0gMikpICsgY29vcmRfZmxpcCgpDQpwQmFyDQoNCmlmIChzYXZlcGxvdHMpew0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QU5vdGljZVNoYXJwQ29uUGVybWltcC5zdmciLCB3aWR0aD04LCBoZWlnaHQ9NC45LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAic3ZnIikpDQogIHVubGluaygiUHRBTm90aWNlU2hhcnBDb25QZXJtaW1wLnN2ZyIpDQogIA0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QU5vdGljZVNoYXJwQ29uUGVybWltcC5wZGYiLCB3aWR0aD04LCBoZWlnaHQ9NC45LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAicGRmIikpDQogIHVubGluaygiUHRBTm90aWNlU2hhcnBDb25QZXJtaW1wLnBkZiIpDQp9DQoNCg0KYGBgDQoNClNlbGVjdGVkIG1ldHJpYw0KDQpgYGB7cn0NCg0Kc2hhcnBWYXIgPC0gIlVBU1NoYXJwQXVySVNPMzA1RXhNYXhMUiINCg0KDQpgYGANCg0KIyMjIyMgVG9uYWwgbG91ZG5lc3MgYW5kIHRvbmFsaXR5DQoNCiMjIyMjIyBTZXQgdmFyaWFibGVzDQoNCmBgYHtyfQ0KDQppVmFycyA8LSBjKGFic1ZhciwgIkFtYmllbnRMQWVxIiwgIlVBU1RvbmFsRUNNQUF2Z01heExSIiwgIlVBU1RvbmFsU0hNSW50MDVFeE1heExSIiwgIlVBU1RvbmFsU0hNSW50QXZnTWF4TFIiLCAiVUFTVG9uYWxFQ01BMDVFeE1heExSIiwgIlVBU1RvbkxkRUNNQVBvd0F2Z0JpbiIsICJVQVNUb25MZEVDTUEwNUV4QmluIiwgIlVBU1RvbmFsQXVyQXZnTWF4TFIiLCAiVUFTVG9uYWxBdXIwNUV4TWF4TFIiLCAiVUFTVG9uYWxBdXIxMEV4TWF4TFIiKQ0KZFZhciA8LSAiTm90aWNlZFBjRmlsdCINCg0Kc2VlZHMgPC0gYyg1NDAsIDEwNDc5OCwgNDU2NDY0LCA4NzMzMSwgOTQ1NjQpDQoNCmBgYA0KDQojIyMjIyMgSHlwZXJwYXJhbWV0ZXIgdHVuaW5nDQoNCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NH0NCg0KcCA8LSBtdHJ5VHVuZShkYXRhSW49c3RpbU5vdGljZURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkPXNlZWRzWzFdLA0KICAgICAgICAgICAgIG50cmVlcz1udHJlZXMsIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KcA0KDQpgYGANCg0KU2VsZWN0ZWQgaHlwZXJwYXJhbWV0ZXJzDQoNCmBgYHtyfQ0KDQpudHJlZSA8LSAxNTAxDQptdHJ5IDwtIGFzLmludGVnZXIobGVuZ3RoKGlWYXJzKS8xLjI1KQ0KDQpgYGANCg0KDQojIyMjIyMgUnVuIG1vZGVsDQoNClRyYWluIHByZWxpbWluYXJ5IG1vZGVsDQoNCmBgYHtyfQ0KIyBUb25hbGl0eSB3aXRoIHRvbmFsIGxvdWRuZXNzDQoNCm5wZXJtIDwtIDUNCg0KcmVzdWx0c091dFRvbmFsMSA8LSBjcmZSZWcoZGF0YUluPXN0aW1Ob3RpY2VEYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHNbMToyXSwgbnRyZWU9bnRyZWUsIG10cnk9bXRyeSwgcGVybUltcENvbmRUaHJlcz1wZXJtSW1wQ29uZFRocmVzLCBucGVybT1ucGVybSwgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQoNCiMgcHJpbnQgbW9kZWwgcHJlZGljdGlvbiByZXN1bHRzDQpyZXN1bHRzT3V0VG9uYWwxJE9PQl9STVNFDQpyZXN1bHRzT3V0VG9uYWwxJE9PQl9NQUUNCnJlc3VsdHNPdXRUb25hbDEkUnNxdWFyZWQNCmBgYA0KVHJhaW4gbXVsdGlwbGUgc2VlZHMgbW9kZWwNCg0KYGBge3J9DQojIFRvbmFsaXR5IHdpdGggdG9uYWwgbG91ZG5lc3MNCg0KcmVzdWx0c091dFRvbmFsMSA8LSBtdWx0aV9jcmZSZWcoZGF0YUluPXN0aW1Ob3RpY2VEYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHMsIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dFRvbmFsMSRPT0JfUk1TRQ0KcmVzdWx0c091dFRvbmFsMSRPT0JfTUFFDQpyZXN1bHRzT3V0VG9uYWwxJFJzcXVhcmVkDQoNCmBgYA0KDQpgYGB7cn0NCiMgc3RvcmUgcmVzdWx0cw0KcmVzTm90aWNlRml0WydBYnMgdG9uYWwgaW5jIGxvdWQnLCAnUk1TRSddIDwtIHJlc3VsdHNPdXRUb25hbDEkT09CX1JNU0UNCnJlc05vdGljZUZpdFsnQWJzIHRvbmFsIGluYyBsb3VkJywgJ01BRSddIDwtIHJlc3VsdHNPdXRUb25hbDEkT09CX01BRQ0KcmVzTm90aWNlRml0WydBYnMgdG9uYWwgaW5jIGxvdWQnLCAnUnNxdWFyZWQnXSA8LSByZXN1bHRzT3V0VG9uYWwxJFJzcXVhcmVkDQpyZXNOb3RpY2VQZXJtSW1wJEFic1RvbmFsMSA8LSByZXN1bHRzT3V0VG9uYWwxJGNvbmRpdGlvbmFsX3Blcm1pbXANCg0KYGBgDQoNCiMjIyMjIyBQbG90IHJlc3VsdHMNCg0KYGBge3IsIGZpZy53aWR0aD04LGZpZy5oZWlnaHQ9My44fQ0KDQpwYXIobWFpPWMoMCwzLDAsMCkpDQoNCiMgcGxvdCBjb25kaXRpb25hbCBpbXBvcnRhbmNlDQpyZXN1bHRzT3V0VG9uYWwxLmNvbmltcCA8LSBhcnJhbmdlKHJlc3VsdHNPdXRUb25hbDEkY29uZGl0aW9uYWxfcGVybWltcCwgZGVzYyhyb3dfbnVtYmVyKCkpKQ0KDQpwQmFyIDwtIGdncGxvdChyZXN1bHRzT3V0VG9uYWwxLmNvbmltcCkgKyBnZW9tX2NvbChhZXMoeD1mYWN0b3Iocm93bmFtZXMocmVzdWx0c091dFRvbmFsMS5jb25pbXApLCBsZXZlbHM9cm93bmFtZXMocmVzdWx0c091dFRvbmFsMS5jb25pbXApKSwgeT1Db25kUGVybUltcCksIGZpbGw9bXljb2xvdXJzWzNdLCB3aWR0aD0wLjUpICsgbGFicyh4PSJWYXJpYWJsZSIsIHk9IkNvbmRpdGlvbmFsIHZhcmlhYmxlIHBlcm11dGF0aW9uIGltcG9ydGFuY2UgKCUgVUFTIG5vdGljZWQpIikgKyBnZ3RpdGxlKCJUb25hbGl0eSBpbmMuIHRvbmFsIGxvdWRuZXNzIikgKyB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIpLCBwYW5lbC5ncmlkPWVsZW1lbnRfbGluZShjb2xvciA9IHJnYigyMzUsIDIzNSwgMjM1LCAxMDAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCBsaW5ld2lkdGggPSAwLjI1LCBsaW5ldHlwZSA9IDIpKSArIGNvb3JkX2ZsaXAoeWxpbT1jKC0xLCAxMDAwKSkNCnBCYXINCg0KaWYgKHNhdmVwbG90cyl7DQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBTm90aWNlVG9uYWxMZENvblBlcm1pbXAuc3ZnIiwgd2lkdGg9OCwgaGVpZ2h0PTMuOCwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInN2ZyIpKQ0KICB1bmxpbmsoIlB0QU5vdGljZVRvbmFsTGRDb25QZXJtaW1wLnN2ZyIpDQogIA0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QU5vdGljZVRvbmFsTGRDb25QZXJtaW1wLnBkZiIsIHdpZHRoPTgsIGhlaWdodD0zLjgsIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJwZGYiKSkNCiAgdW5saW5rKCJQdEFOb3RpY2VUb25hbExkQ29uUGVybWltcC5wZGYiKQ0KfQ0KDQpgYGANCg0KU2VsZWN0ZWQgbWV0cmljDQoNCmBgYHtyfQ0KDQp0b25MZFZhciA8LSAiVUFTVG9uTGRFQ01BMDVFeEJpbiINCg0KYGBgDQoNCiMjIyMjIFRvbmFsaXR5IHdpdGhvdXQgdG9uYWwgbG91ZG5lc3MNCg0KIyMjIyMjIFNldCB2YXJpYWJsZXMNCg0KYGBge3J9DQoNCmlWYXJzIDwtIGMoYWJzVmFyLCAiQW1iaWVudExBZXEiLCAiVUFTVG9uYWxFQ01BQXZnTWF4TFIiLCAiVUFTVG9uYWxTSE1JbnQwNUV4TWF4TFIiLCAiVUFTVG9uYWxTSE1JbnRBdmdNYXhMUiIsICJVQVNUb25hbEVDTUEwNUV4TWF4TFIiLCAiVUFTVG9uYWxBdXJBdmdNYXhMUiIsICJVQVNUb25hbEF1cjA1RXhNYXhMUiIsICJVQVNUb25hbEF1cjEwRXhNYXhMUiIpDQpkVmFyIDwtICJOb3RpY2VkUGNGaWx0Ig0KDQpzZWVkcyA8LSBjKDE1NjA4OSwgNTg2MCwgMTA1MjgsIDg5NTQxLCA0Njg1MTQ2KQ0KDQpgYGANCg0KIyMjIyMjIEh5cGVycGFyYW1ldGVyIHR1bmluZw0KDQpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTR9DQoNCnAgPC0gbXRyeVR1bmUoZGF0YUluPXN0aW1Ob3RpY2VEYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZD1zZWVkc1sxXSwNCiAgICAgICAgICAgICBudHJlZXM9bnRyZWVzLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCnANCg0KYGBgDQoNClNlbGVjdGVkIGh5cGVycGFyYW1ldGVycw0KDQpgYGB7cn0NCg0KbnRyZWUgPC0gNTUwMQ0KbXRyeSA8LSBhcy5pbnRlZ2VyKGxlbmd0aChpVmFycykvMS4yNSkNCg0KYGBgDQoNCg0KIyMjIyMjIFJ1biBtb2RlbA0KDQpUcmFpbiBwcmVsaW1pbmFyeSBtb2RlbA0KDQpgYGB7cn0NCiMgVG9uYWxpdHkNCg0KbnBlcm0gPC0gNQ0KDQpyZXN1bHRzT3V0VG9uYWwyIDwtIGNyZlJlZyhkYXRhSW49c3RpbU5vdGljZURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkc1sxOjJdLCBudHJlZT1udHJlZSwgbXRyeT1tdHJ5LCBwZXJtSW1wQ29uZFRocmVzPXBlcm1JbXBDb25kVGhyZXMsIG5wZXJtPW5wZXJtLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCg0KIyBwcmludCBtb2RlbCBwcmVkaWN0aW9uIHJlc3VsdHMNCnJlc3VsdHNPdXRUb25hbDIkT09CX1JNU0UNCnJlc3VsdHNPdXRUb25hbDIkT09CX01BRQ0KcmVzdWx0c091dFRvbmFsMiRSc3F1YXJlZA0KDQpgYGANCg0KVHJhaW4gbXVsdGlwbGUgc2VlZHMgbW9kZWwNCg0KYGBge3J9DQojIFRvbmFsaXR5DQoNCnJlc3VsdHNPdXRUb25hbDIgPC0gbXVsdGlfY3JmUmVnKGRhdGFJbj1zdGltTm90aWNlRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzLCBudHJlZT1udHJlZSwgbXRyeT1tdHJ5LCBwZXJtSW1wQ29uZFRocmVzPXBlcm1JbXBDb25kVGhyZXMsIG5wZXJtPW5wZXJtLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCg0KIyBwcmludCBtb2RlbCBwcmVkaWN0aW9uIHJlc3VsdHMNCnJlc3VsdHNPdXRUb25hbDIkT09CX1JNU0UNCnJlc3VsdHNPdXRUb25hbDIkT09CX01BRQ0KcmVzdWx0c091dFRvbmFsMiRSc3F1YXJlZA0KDQpgYGANCg0KDQpgYGB7cn0NCg0KIyBzdG9yZSByZXN1bHRzDQpyZXNOb3RpY2VGaXRbJ0FicyB0b25hbCBubyBsb3VkJywgJ1JNU0UnXSA8LSByZXN1bHRzT3V0VG9uYWwyJE9PQl9STVNFDQpyZXNOb3RpY2VGaXRbJ0FicyB0b25hbCBubyBsb3VkJywgJ01BRSddIDwtIHJlc3VsdHNPdXRUb25hbDIkT09CX01BRQ0KcmVzTm90aWNlRml0WydBYnMgdG9uYWwgbm8gbG91ZCcsICdSc3F1YXJlZCddIDwtIHJlc3VsdHNPdXRUb25hbDIkUnNxdWFyZWQNCnJlc05vdGljZVBlcm1JbXAkQWJzVG9uYWwyIDwtIHJlc3VsdHNPdXRUb25hbDIkY29uZGl0aW9uYWxfcGVybWltcA0KDQpgYGANCg0KIyMjIyMjIFBsb3QgcmVzdWx0cw0KDQpgYGB7ciwgZmlnLndpZHRoPTgsZmlnLmhlaWdodD0zLjJ9DQpwYXIobWFpPWMoMCwzLDAsMCkpDQoNCiMgcGxvdCBjb25kaXRpb25hbCBpbXBvcnRhbmNlDQpyZXN1bHRzT3V0VG9uYWwyLmNvbmltcCA8LSBhcnJhbmdlKHJlc3VsdHNPdXRUb25hbDIkY29uZGl0aW9uYWxfcGVybWltcCwgZGVzYyhyb3dfbnVtYmVyKCkpKQ0KDQpwQmFyIDwtIGdncGxvdChyZXN1bHRzT3V0VG9uYWwyLmNvbmltcCkgKyBnZW9tX2NvbChhZXMoeD1mYWN0b3Iocm93bmFtZXMocmVzdWx0c091dFRvbmFsMi5jb25pbXApLCBsZXZlbHM9cm93bmFtZXMocmVzdWx0c091dFRvbmFsMi5jb25pbXApKSwgeT1Db25kUGVybUltcCksIGZpbGw9bXljb2xvdXJzWzNdLCB3aWR0aD0wLjUpICsgbGFicyh4PSJWYXJpYWJsZSIsIHk9IkNvbmRpdGlvbmFsIHZhcmlhYmxlIHBlcm11dGF0aW9uIGltcG9ydGFuY2UgKCUgVUFTIG5vdGljZWQpIikgKyBnZ3RpdGxlKCJUb25hbGl0eSB3L28gdG9uYWwgbG91ZG5lc3MiKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiksIHBhbmVsLmdyaWQ9ZWxlbWVudF9saW5lKGNvbG9yID0gcmdiKDIzNSwgMjM1LCAyMzUsIDEwMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksIGxpbmV3aWR0aCA9IDAuMjUsIGxpbmV0eXBlID0gMikpICsgY29vcmRfZmxpcCh5bGltPWMoLTEsIDEwMDApKQ0KcEJhcg0KDQppZiAoc2F2ZXBsb3RzKXsNCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFOb3RpY2VUb25hbENvblBlcm1pbXAuc3ZnIiwgd2lkdGg9OCwgaGVpZ2h0PTMuMiwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInN2ZyIpKQ0KICB1bmxpbmsoIlB0QU5vdGljZVRvbmFsQ29uUGVybWltcC5zdmciKQ0KICANCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFOb3RpY2VUb25hbENvblBlcm1pbXAucGRmIiwgd2lkdGg9OCwgaGVpZ2h0PTMuMiwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInBkZiIpKQ0KICB1bmxpbmsoIlB0QU5vdGljZVRvbmFsQ29uUGVybWltcC5wZGYiKQ0KfQ0KDQoNCmBgYA0KDQpTZWxlY3RlZCBtZXRyaWMNCg0KYGBge3J9DQoNCnRvbmFsVmFyIDwtICJVQVNUb25hbFNITUludDA1RXhNYXhMUiINCg0KYGBgDQoNCiMjIyMjIEZsdWN0dWF0aW9uIHN0cmVuZ3RoDQoNCiMjIyMjIyBTZXQgdmFyaWFibGVzDQoNCmBgYHtyfQ0KDQojIEZsdWN0dWF0aW9uIHN0cmVuZ3RoDQppVmFycyA8LSBjKGFic1ZhciwgIkFtYmllbnRMQWVxIiwgIlVBU0ZsdWN0U0hNMTBFeEJpbiIsICJVQVNGbHVjdFNITTA1RXhCaW4iLCAiVUFTRmx1Y3RGWjEwRXhNYXhMUiIsICJVQVNGbHVjdEZaMDVFeE1heExSIiwgIlVBU0ZsdWN0T1YxMEV4TWF4TFIiLCAiVUFTRmx1Y3RPVjA1RXhNYXhMUiIpDQpkVmFyIDwtICJOb3RpY2VkUGNGaWx0Ig0KDQpzZWVkcyA8LSBjKDI1MTA3LCA1NDYwOTgsIDE5NSwgNTkzNywgMTAyNjU4KQ0KDQpgYGANCg0KDQojIyMjIyMgSHlwZXJwYXJhbWV0ZXIgdHVuaW5nDQoNCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NH0NCg0KcCA8LSBtdHJ5VHVuZShkYXRhSW49c3RpbU5vdGljZURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkPXNlZWRzWzFdLA0KICAgICAgICAgICAgIG50cmVlcz1udHJlZXMsIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KcA0KDQpgYGANCg0KU2VsZWN0ZWQgaHlwZXJwYXJhbWV0ZXJzDQoNCmBgYHtyfQ0KDQpudHJlZSA8LSAyNTENCm10cnkgPC0gYXMuaW50ZWdlcihsZW5ndGgoaVZhcnMpLzEuNSkNCg0KYGBgDQoNCg0KIyMjIyMjIFJ1biBtb2RlbA0KDQpUcmFpbiBwcmVsaW1pbmFyeSBtb2RlbA0KDQpgYGB7cn0NCg0KbnBlcm0gPC0gNQ0KDQpyZXN1bHRzT3V0Rmx1Y3QgPC0gY3JmUmVnKGRhdGFJbj1zdGltTm90aWNlRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzWzE6Ml0sIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dEZsdWN0JE9PQl9STVNFDQpyZXN1bHRzT3V0Rmx1Y3QkT09CX01BRQ0KcmVzdWx0c091dEZsdWN0JFJzcXVhcmVkDQoNCmBgYA0KVHJhaW4gbXVsdGlwbGUgc2VlZHMgbW9kZWwNCg0KYGBge3J9DQoNCnJlc3VsdHNPdXRGbHVjdCA8LSBtdWx0aV9jcmZSZWcoZGF0YUluPXN0aW1Ob3RpY2VEYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHMsIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dEZsdWN0JE9PQl9STVNFDQpyZXN1bHRzT3V0Rmx1Y3QkT09CX01BRQ0KcmVzdWx0c091dEZsdWN0JFJzcXVhcmVkDQoNCmBgYA0KDQoNCmBgYHtyfQ0KDQojIHN0b3JlIHJlc3VsdHMNCnJlc05vdGljZUZpdFsnQWJzIGZsdWN0JywgJ1JNU0UnXSA8LSByZXN1bHRzT3V0Rmx1Y3QkT09CX1JNU0UNCnJlc05vdGljZUZpdFsnQWJzIGZsdWN0JywgJ01BRSddIDwtIHJlc3VsdHNPdXRGbHVjdCRPT0JfTUFFDQpyZXNOb3RpY2VGaXRbJ0FicyBmbHVjdCcsICdSc3F1YXJlZCddIDwtIHJlc3VsdHNPdXRGbHVjdCRSc3F1YXJlZA0KcmVzTm90aWNlUGVybUltcCRBYnNGbHVjdCA8LSByZXN1bHRzT3V0Rmx1Y3QkY29uZGl0aW9uYWxfcGVybWltcA0KDQpgYGANCg0KIyMjIyMjIFBsb3QgcmVzdWx0cw0KDQpgYGB7ciwgZmlnLndpZHRoPTgsZmlnLmhlaWdodD0yLjl9DQpwYXIobWFpPWMoMCwzLDAsMCkpDQoNCiMgcGxvdCBjb25kaXRpb25hbCBpbXBvcnRhbmNlDQpyZXN1bHRzT3V0Rmx1Y3QuY29uaW1wIDwtIGFycmFuZ2UocmVzdWx0c091dEZsdWN0JGNvbmRpdGlvbmFsX3Blcm1pbXAsIGRlc2Mocm93X251bWJlcigpKSkNCg0KcEJhciA8LSBnZ3Bsb3QocmVzdWx0c091dEZsdWN0LmNvbmltcCkgKyBnZW9tX2NvbChhZXMoeD1mYWN0b3Iocm93bmFtZXMocmVzdWx0c091dEZsdWN0LmNvbmltcCksIGxldmVscz1yb3duYW1lcyhyZXN1bHRzT3V0Rmx1Y3QuY29uaW1wKSksIHk9Q29uZFBlcm1JbXApLCBmaWxsPW15Y29sb3Vyc1s0XSwgd2lkdGg9MC41KSArIGxhYnMoeD0iVmFyaWFibGUiLCB5PSJDb25kaXRpb25hbCB2YXJpYWJsZSBwZXJtdXRhdGlvbiBpbXBvcnRhbmNlICglIFVBUyBub3RpY2VkKSIpICsgZ2d0aXRsZSgiRmx1Y3R1YXRpb24gc3RyZW5ndGgiKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiksIHBhbmVsLmdyaWQ9ZWxlbWVudF9saW5lKGNvbG9yID0gcmdiKDIzNSwgMjM1LCAyMzUsIDEwMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksIGxpbmV3aWR0aCA9IDAuMjUsIGxpbmV0eXBlID0gMikpICsgY29vcmRfZmxpcCgpDQpwQmFyDQoNCmlmIChzYXZlcGxvdHMpew0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QU5vdGljZUZsdWN0Q29uUGVybWltcC5zdmciLCB3aWR0aD04LCBoZWlnaHQ9Mi45LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAic3ZnIikpDQogIHVubGluaygiUHRBTm90aWNlRmx1Y3RDb25QZXJtaW1wLnN2ZyIpDQogIA0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QU5vdGljZUZsdWN0Q29uUGVybWltcC5wZGYiLCB3aWR0aD04LCBoZWlnaHQ9Mi45LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAicGRmIikpDQogIHVubGluaygiUHRBTm90aWNlRmx1Y3RDb25QZXJtaW1wLnBkZiIpDQp9DQoNCmBgYA0KDQpTZWxlY3RlZCBtZXRyaWMNCg0KYGBge3J9DQoNCmZsdWN0VmFyIDwtICJVQVNGbHVjdE9WMTBFeE1heExSIg0KDQpgYGANCg0KIyMjIyMgUm91Z2huZXNzDQoNCiMjIyMjIyBTZXQgdmFyaWFibGVzDQoNCmBgYHtyfQ0KDQojIFJvdWdobmVzcw0KaVZhcnMgPC0gYyhhYnNWYXIsICJBbWJpZW50TEFlcSIsICJVQVNSb3VnaEVDTUExMEV4QmluIiwgIlVBU1JvdWdoRUNNQTA1RXhCaW4iLCAiVUFTUm91Z2hGWjEwRXhNYXhMUiIsICJVQVNSb3VnaEZaMDVFeE1heExSIiwgIlVBU1JvdWdoRFcxMEV4TWF4TFIiLCAiVUFTUm91Z2hEVzA1RXhNYXhMUiIpDQpkVmFyIDwtICJOb3RpY2VkUGNGaWx0Ig0KDQpzZWVkcyA8LSBjKDQ3MDEsIDUyMTg3LCAxNjU4OSwgNjUyMTcsIDE2ODkzKQ0KDQpgYGANCg0KIyMjIyMjIEh5cGVycGFyYW1ldGVyIHR1bmluZw0KDQpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTR9DQoNCnAgPC0gbXRyeVR1bmUoZGF0YUluPXN0aW1Ob3RpY2VEYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZD1zZWVkc1sxXSwNCiAgICAgICAgICAgICBudHJlZXM9bnRyZWVzLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCnANCg0KYGBgDQoNClNlbGVjdGVkIGh5cGVycGFyYW1ldGVycw0KDQpgYGB7cn0NCg0KbnRyZWUgPC0gMTAwMQ0KbXRyeSA8LSBhcy5pbnRlZ2VyKGxlbmd0aChpVmFycykvMS4yNSkNCg0KYGBgDQoNCg0KIyMjIyMjIFJ1biBtb2RlbA0KDQpUcmFpbiBwcmVsaW1pbmFyeSBtb2RlbA0KDQpgYGB7cn0NCg0KbnBlcm0gPC0gNQ0KDQpyZXN1bHRzT3V0Um91Z2ggPC0gY3JmUmVnKGRhdGFJbj1zdGltTm90aWNlRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzWzE6Ml0sIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dFJvdWdoJE9PQl9STVNFDQpyZXN1bHRzT3V0Um91Z2gkT09CX01BRQ0KcmVzdWx0c091dFJvdWdoJFJzcXVhcmVkDQoNCmBgYA0KDQpUcmFpbiBtdWx0aXBsZSBzZWVkcyBtb2RlbA0KDQpgYGB7cn0NCg0KcmVzdWx0c091dFJvdWdoIDwtIG11bHRpX2NyZlJlZyhkYXRhSW49c3RpbU5vdGljZURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkcywgbnRyZWU9bnRyZWUsIG10cnk9bXRyeSwgcGVybUltcENvbmRUaHJlcz1wZXJtSW1wQ29uZFRocmVzLCBucGVybT1ucGVybSwgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQoNCiMgcHJpbnQgbW9kZWwgcHJlZGljdGlvbiByZXN1bHRzDQpyZXN1bHRzT3V0Um91Z2gkT09CX1JNU0UNCnJlc3VsdHNPdXRSb3VnaCRPT0JfTUFFDQpyZXN1bHRzT3V0Um91Z2gkUnNxdWFyZWQNCg0KYGBgDQoNCmBgYHtyfQ0KIyBzdG9yZSByZXN1bHRzDQpyZXNOb3RpY2VGaXRbJ0FicyByb3VnaCcsICdSTVNFJ10gPC0gcmVzdWx0c091dFJvdWdoJE9PQl9STVNFDQpyZXNOb3RpY2VGaXRbJ0FicyByb3VnaCcsICdNQUUnXSA8LSByZXN1bHRzT3V0Um91Z2gkT09CX01BRQ0KcmVzTm90aWNlRml0WydBYnMgcm91Z2gnLCAnUnNxdWFyZWQnXSA8LSByZXN1bHRzT3V0Um91Z2gkUnNxdWFyZWQNCnJlc05vdGljZVBlcm1JbXAkQWJzUm91Z2ggPC0gcmVzdWx0c091dFJvdWdoJGNvbmRpdGlvbmFsX3Blcm1pbXANCg0KYGBgDQoNCiMjIyMjIyBQbG90IHJlc3VsdHMNCg0KYGBge3IsIGZpZy53aWR0aD04LGZpZy5oZWlnaHQ9Mi45fQ0KcGFyKG1haT1jKDAsMywwLDApKQ0KDQojIHBsb3QgY29uZGl0aW9uYWwgaW1wb3J0YW5jZQ0KcmVzdWx0c091dFJvdWdoLmNvbmltcCA8LSBhcnJhbmdlKHJlc3VsdHNPdXRSb3VnaCRjb25kaXRpb25hbF9wZXJtaW1wLCBkZXNjKHJvd19udW1iZXIoKSkpDQoNCnBCYXIgPC0gZ2dwbG90KHJlc3VsdHNPdXRSb3VnaC5jb25pbXApICsgZ2VvbV9jb2woYWVzKHg9ZmFjdG9yKHJvd25hbWVzKHJlc3VsdHNPdXRSb3VnaC5jb25pbXApLCBsZXZlbHM9cm93bmFtZXMocmVzdWx0c091dFJvdWdoLmNvbmltcCkpLCB5PUNvbmRQZXJtSW1wKSwgZmlsbD1teWNvbG91cnNbNV0sIHdpZHRoPTAuNSkgKyBsYWJzKHg9IlZhcmlhYmxlIiwgeT0iQ29uZGl0aW9uYWwgdmFyaWFibGUgcGVybXV0YXRpb24gaW1wb3J0YW5jZSAoJSBVQVMgbm90aWNlZCkiKSArIGdndGl0bGUoIlJvdWdobmVzcyIpICsgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2VyaWYiKSwgcGFuZWwuZ3JpZD1lbGVtZW50X2xpbmUoY29sb3IgPSByZ2IoMjM1LCAyMzUsIDIzNSwgMTAwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgbGluZXdpZHRoID0gMC4yNSwgbGluZXR5cGUgPSAyKSkgKyBjb29yZF9mbGlwKCkNCnBCYXINCg0KaWYgKHNhdmVwbG90cyl7DQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBTm90aWNlUm91Z2hDb25QZXJtaW1wLnN2ZyIsIHdpZHRoPTgsIGhlaWdodD0yLjksIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJzdmciKSkNCiAgdW5saW5rKCJQdEFOb3RpY2VSb3VnaENvblBlcm1pbXAuc3ZnIikNCiAgDQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBTm90aWNlUm91Z2hDb25QZXJtaW1wLnBkZiIsIHdpZHRoPTgsIGhlaWdodD0yLjksIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJwZGYiKSkNCiAgdW5saW5rKCJQdEFOb3RpY2VSb3VnaENvblBlcm1pbXAucGRmIikNCn0NCg0KDQpgYGANCg0KU2VsZWN0ZWQgbWV0cmljDQoNCmBgYHtyfQ0KDQpyb3VnaFZhciA8LSAiVUFTUm91Z2hGWjA1RXhNYXhMUiINCg0KYGBgDQoNCg0KIyMjIyMgSW1wdWxzaXZlbmVzcw0KDQojIyMjIyMgU2V0IHZhcmlhYmxlcw0KDQpgYGB7cn0NCiMgSW1wdWxzaXZlbmVzcw0KaVZhcnMgPC0gYyhhYnNWYXIsICJBbWJpZW50TEFlcSIsICJVQVNJbXB1bHNTSE1BdmdNYXhMUiIsICJVQVNJbXB1bHNTSE0wNUV4TWF4TFIiLCAiVUFTSW1wdWxzU0hNUG93QXZnTWF4TFIiKQ0KZFZhciA8LSAiTm90aWNlZFBjRmlsdCINCg0Kc2VlZHMgPC0gYyg4NDk1LCA1OTg2NywgNTQxNiwgOTg0MywgODYpDQoNCmBgYA0KDQojIyMjIyMgSHlwZXJwYXJhbWV0ZXIgdHVuaW5nDQoNCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NH0NCg0KcCA8LSBtdHJ5VHVuZShkYXRhSW49c3RpbU5vdGljZURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkPXNlZWRzWzFdLA0KICAgICAgICAgICAgIG50cmVlcz1udHJlZXMsIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KcA0KDQpgYGANCg0KU2VsZWN0ZWQgaHlwZXJwYXJhbWV0ZXJzDQoNCmBgYHtyfQ0KDQpudHJlZSA8LSA1NTAxDQptdHJ5IDwtIGFzLmludGVnZXIobGVuZ3RoKGlWYXJzKS8xLjI1KQ0KDQpgYGANCg0KDQojIyMjIyMgUnVuIG1vZGVsDQoNClRyYWluIHByZWxpbWluYXJ5IG1vZGVsDQoNCmBgYHtyfQ0KDQpucGVybSA8LSA1DQoNCnJlc3VsdHNPdXRJbXB1bHMgPC0gY3JmUmVnKGRhdGFJbj1zdGltTm90aWNlRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzWzE6Ml0sIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dEltcHVscyRPT0JfUk1TRQ0KcmVzdWx0c091dEltcHVscyRPT0JfTUFFDQpyZXN1bHRzT3V0SW1wdWxzJFJzcXVhcmVkDQoNCmBgYA0KDQpUcmFpbiBtdWx0aXBsZSBzZWVkcyBtb2RlbA0KDQpgYGB7cn0NCg0KcmVzdWx0c091dEltcHVscyA8LSBtdWx0aV9jcmZSZWcoZGF0YUluPXN0aW1Ob3RpY2VEYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHMsIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dEltcHVscyRPT0JfUk1TRQ0KcmVzdWx0c091dEltcHVscyRPT0JfTUFFDQpyZXN1bHRzT3V0SW1wdWxzJFJzcXVhcmVkDQoNCmBgYA0KDQpgYGB7cn0NCg0KIyBzdG9yZSByZXN1bHRzDQpyZXNOb3RpY2VGaXRbJ0FicyBpbXB1bHMnLCAnUk1TRSddIDwtIHJlc3VsdHNPdXRJbXB1bHMkT09CX1JNU0UNCnJlc05vdGljZUZpdFsnQWJzIGltcHVscycsICdNQUUnXSA8LSByZXN1bHRzT3V0SW1wdWxzJE9PQl9NQUUNCnJlc05vdGljZUZpdFsnQWJzIGltcHVscycsICdSc3F1YXJlZCddIDwtIHJlc3VsdHNPdXRJbXB1bHMkUnNxdWFyZWQNCnJlc05vdGljZVBlcm1JbXAkQWJzSW1wdWxzIDwtIHJlc3VsdHNPdXRJbXB1bHMkY29uZGl0aW9uYWxfcGVybWltcA0KDQpgYGANCg0KIyMjIyMjIFBsb3QgcmVzdWx0cw0KDQpgYGB7ciwgZmlnLndpZHRoPTgsZmlnLmhlaWdodD0yfQ0KcGFyKG1haT1jKDAsMywwLDApKQ0KDQojIHBsb3QgY29uZGl0aW9uYWwgaW1wb3J0YW5jZQ0KcmVzdWx0c091dEltcHVscy5jb25pbXAgPC0gYXJyYW5nZShyZXN1bHRzT3V0SW1wdWxzJGNvbmRpdGlvbmFsX3Blcm1pbXAsIGRlc2Mocm93X251bWJlcigpKSkNCg0KcEJhciA8LSBnZ3Bsb3QocmVzdWx0c091dEltcHVscy5jb25pbXApICsgZ2VvbV9jb2woYWVzKHg9ZmFjdG9yKHJvd25hbWVzKHJlc3VsdHNPdXRJbXB1bHMuY29uaW1wKSwgbGV2ZWxzPXJvd25hbWVzKHJlc3VsdHNPdXRJbXB1bHMuY29uaW1wKSksIHk9Q29uZFBlcm1JbXApLCBmaWxsPW15Y29sb3Vyc1s2XSwgd2lkdGg9MC41KSArIGxhYnMoeD0iVmFyaWFibGUiLCB5PSJDb25kaXRpb25hbCB2YXJpYWJsZSBwZXJtdXRhdGlvbiBpbXBvcnRhbmNlICglIFVBUyBub3RpY2VkKSIpICsgZ2d0aXRsZSgiSW1wdWxzaXZlbmVzcyIpICsgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2VyaWYiKSwgcGFuZWwuZ3JpZD1lbGVtZW50X2xpbmUoY29sb3IgPSByZ2IoMjM1LCAyMzUsIDIzNSwgMTAwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgbGluZXdpZHRoID0gMC4yNSwgbGluZXR5cGUgPSAyKSkgKyBjb29yZF9mbGlwKCkNCnBCYXINCg0KaWYgKHNhdmVwbG90cyl7DQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBTm90aWNlSW1wdWxzQ29uUGVybWltcC5zdmciLCB3aWR0aD04LCBoZWlnaHQ9MiwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInN2ZyIpKQ0KICB1bmxpbmsoIlB0QU5vdGljZUltcHVsc0NvblBlcm1pbXAuc3ZnIikNCiAgDQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBTm90aWNlSW1wdWxzQ29uUGVybWltcC5wZGYiLCB3aWR0aD04LCBoZWlnaHQ9MiwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInBkZiIpKQ0KICB1bmxpbmsoIlB0QU5vdGljZUltcHVsc0NvblBlcm1pbXAucGRmIikNCn0NCg0KYGBgDQoNClNlbGVjdGVkIG1ldHJpYw0KDQpgYGB7cn0NCg0KaW1wdWxzVmFyIDwtICJVQVNJbXB1bHNTSE1BdmdNYXhMUiINCg0KYGBgDQoNCiMjIyMgU1FNIGFuZCBsb3VkbmVzcyBjb21wYXJpc29uDQoNCk5vdyB0aGUgaGlnaGVzdCBpbXBvcnRhbmNlIFNRTXMgYXJlIHJhbmtlZCBhZ2FpbnN0IGVhY2ggb3RoZXIsIGNvbnRyb2xsaW5nIGZvciBVQVMgbG91ZG5lc3MgYW5kIGFtYmllbnQgTEFlcS4NCg0KIyMjIyMgSW5jbHVkZSB0b25hbCBsb3VkbmVzcw0KDQojIyMjIyMgU2V0IHZhcmlhYmxlcw0KDQpgYGB7cn0NCg0KaVZhcnMgPC0gYyhhYnNWYXIsICJBbWJpZW50TEFlcSIsIHNoYXJwVmFyLCB0b25MZFZhciwgZmx1Y3RWYXIsIHJvdWdoVmFyLCBpbXB1bHNWYXIpDQpkVmFyIDwtICJOb3RpY2VkUGNGaWx0Ig0KDQpzZWVkcyA8LSBjKDcwNDk4LCA0LCAxNDk4NiwgNDUzLCA4NjQpDQoNCmBgYA0KDQojIyMjIyMgSHlwZXJwYXJhbWV0ZXIgdHVuaW5nDQoNCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NH0NCg0KcCA8LSBtdHJ5VHVuZShkYXRhSW49c3RpbU5vdGljZURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkPXNlZWRzWzFdLA0KICAgICAgICAgICAgIG50cmVlcz1udHJlZXMsIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KcA0KDQpgYGANCg0KU2VsZWN0ZWQgaHlwZXJwYXJhbWV0ZXJzDQoNCmBgYHtyfQ0KDQpudHJlZSA8LSAyNTENCm10cnkgPC0gYXMuaW50ZWdlcihsZW5ndGgoaVZhcnMpLzEuMjUpDQoNCmBgYA0KDQojIyMjIyMgUnVuIG1vZGVsDQoNClRyYWluIHByZWxpbWluYXJ5IG1vZGVsDQoNCmBgYHtyfQ0KDQpucGVybSA8LSA1DQoNCnJlc3VsdHNPdXRTUU1zMSA8LSBjcmZSZWcoZGF0YUluPXN0aW1Ob3RpY2VEYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHNbMToyXSwgbnRyZWU9bnRyZWUsIG10cnk9bXRyeSwgcGVybUltcENvbmRUaHJlcz1wZXJtSW1wQ29uZFRocmVzLCBucGVybT1ucGVybSwgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQoNCiMgcHJpbnQgbW9kZWwgcHJlZGljdGlvbiByZXN1bHRzDQpyZXN1bHRzT3V0U1FNczEkT09CX1JNU0UNCnJlc3VsdHNPdXRTUU1zMSRPT0JfTUFFDQpyZXN1bHRzT3V0U1FNczEkUnNxdWFyZWQNCg0KYGBgDQoNClRyYWluIG11bHRpcGxlIHNlZWRzIG1vZGVsDQoNCmBgYHtyfQ0KDQpyZXN1bHRzT3V0U1FNczEgPC0gbXVsdGlfY3JmUmVnKGRhdGFJbj1zdGltTm90aWNlRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzLCBudHJlZT1udHJlZSwgbXRyeT1tdHJ5LCBwZXJtSW1wQ29uZFRocmVzPXBlcm1JbXBDb25kVGhyZXMsIG5wZXJtPW5wZXJtLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCg0KIyBwcmludCBtb2RlbCBwcmVkaWN0aW9uIHJlc3VsdHMNCnJlc3VsdHNPdXRTUU1zMSRPT0JfUk1TRQ0KcmVzdWx0c091dFNRTXMxJE9PQl9NQUUNCnJlc3VsdHNPdXRTUU1zMSRSc3F1YXJlZA0KDQpgYGANCg0KYGBge3J9DQoNCiMgc3RvcmUgcmVzdWx0cw0KcmVzTm90aWNlRml0WydBYnMgU1FNcyBpbmMgdG9uYWwgbG91ZCcsICdSTVNFJ10gPC0gcmVzdWx0c091dFNRTXMxJE9PQl9STVNFDQpyZXNOb3RpY2VGaXRbJ0FicyBTUU1zIGluYyB0b25hbCBsb3VkJywgJ01BRSddIDwtIHJlc3VsdHNPdXRTUU1zMSRPT0JfTUFFDQpyZXNOb3RpY2VGaXRbJ0FicyBTUU1zIGluYyB0b25hbCBsb3VkJywgJ1JzcXVhcmVkJ10gPC0gcmVzdWx0c091dFNRTXMxJFJzcXVhcmVkDQpyZXNOb3RpY2VQZXJtSW1wJEFic1NRTXMxIDwtIHJlc3VsdHNPdXRTUU1zMSRjb25kaXRpb25hbF9wZXJtaW1wDQoNCmBgYA0KDQojIyMjIyMgUGxvdCByZXN1bHRzDQoNCmBgYHtyLCBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTIuNH0NCnBhcihtYWk9YygwLDMsMCwwKSkNCg0KIyBwbG90IGNvbmRpdGlvbmFsIGltcG9ydGFuY2UNCnJlc3VsdHNPdXRTUU1zMS5jb25pbXAgPC0gYXJyYW5nZShyZXN1bHRzT3V0U1FNczEkY29uZGl0aW9uYWxfcGVybWltcCwgZGVzYyhyb3dfbnVtYmVyKCkpKQ0KDQpwQmFyIDwtIGdncGxvdChyZXN1bHRzT3V0U1FNczEuY29uaW1wKSArIGdlb21fY29sKGFlcyh4PWZhY3Rvcihyb3duYW1lcyhyZXN1bHRzT3V0U1FNczEuY29uaW1wKSwgbGV2ZWxzPXJvd25hbWVzKHJlc3VsdHNPdXRTUU1zMS5jb25pbXApKSwgeT1Db25kUGVybUltcCksIGZpbGw9bXljb2xvdXJzWzddLCB3aWR0aD0wLjUpICsgbGFicyh4PSJWYXJpYWJsZSIsIHk9IkNvbmRpdGlvbmFsIHZhcmlhYmxlIHBlcm11dGF0aW9uIGltcG9ydGFuY2UgKCUgVUFTIG5vdGljZWQpIikgKyB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIpLCBwYW5lbC5ncmlkPWVsZW1lbnRfbGluZShjb2xvciA9IHJnYigyMzUsIDIzNSwgMjM1LCAxMDAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCBsaW5ld2lkdGggPSAwLjI1LCBsaW5ldHlwZSA9IDIpKSArIGNvb3JkX2ZsaXAoeWxpbT1jKC0xLCA4MDApKQ0KcEJhcg0KDQppZiAoc2F2ZXBsb3RzKXsNCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFOb3RpY2VBYnNTUU1zVG9uTGRDb25QZXJtaW1wLnN2ZyIsIHdpZHRoPTgsIGhlaWdodD0yLjQsIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJzdmciKSkNCiAgdW5saW5rKCJQdEFOb3RpY2VBYnNTUU1zVG9uTGRDb25QZXJtaW1wLnN2ZyIpDQogIA0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QU5vdGljZUFic1NRTXNUb25MZENvblBlcm1pbXAucGRmIiwgd2lkdGg9OCwgaGVpZ2h0PTIuNCwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInBkZiIpKQ0KICB1bmxpbmsoIlB0QU5vdGljZUFic1NRTXNUb25MZENvblBlcm1pbXAucGRmIikNCn0NCg0KYGBgDQoNCiMjIyMjIEV4Y2x1ZGUgdG9uYWwgbG91ZG5lc3MNCg0KIyMjIyMjIFNldCB2YXJpYWJsZXMNCg0KYGBge3J9DQoNCmlWYXJzIDwtIGMoYWJzVmFyLCAiQW1iaWVudExBZXEiLCBzaGFycFZhciwgdG9uYWxWYXIsIGZsdWN0VmFyLCByb3VnaFZhciwgaW1wdWxzVmFyKQ0KZFZhciA8LSAiTm90aWNlZFBjRmlsdCINCg0Kc2VlZHMgPC0gYyg1NDYsIDU3MjAzLCAyNzA4MzUsIDYwNTkyLCA4MDk0KQ0KDQpgYGANCg0KIyMjIyMjIEh5cGVycGFyYW1ldGVyIHR1bmluZw0KDQpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTR9DQoNCnAgPC0gbXRyeVR1bmUoZGF0YUluPXN0aW1Ob3RpY2VEYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZD1zZWVkc1sxXSwNCiAgICAgICAgICAgICBudHJlZXM9bnRyZWVzLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCnANCg0KYGBgDQoNClNlbGVjdGVkIGh5cGVycGFyYW1ldGVycw0KDQpgYGB7cn0NCg0KbnRyZWUgPC0gMjUwMQ0KbXRyeSA8LSBhcy5pbnRlZ2VyKGxlbmd0aChpVmFycykvMS4yNSkNCg0KYGBgDQoNCg0KIyMjIyMjIFJ1biBtb2RlbA0KDQpUcmFpbiBwcmVsaW1pbmFyeSBtb2RlbA0KDQpgYGB7cn0NCg0KbnBlcm0gPC0gNQ0KDQpyZXN1bHRzT3V0U1FNczIgPC0gY3JmUmVnKGRhdGFJbj1zdGltTm90aWNlRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzWzE6Ml0sIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dFNRTXMyJE9PQl9STVNFDQpyZXN1bHRzT3V0U1FNczIkT09CX01BRQ0KcmVzdWx0c091dFNRTXMyJFJzcXVhcmVkDQoNCmBgYA0KDQpUcmFpbiBtdWx0aXBsZSBzZWVkcyBtb2RlbA0KDQpgYGB7cn0NCg0KcmVzdWx0c091dFNRTXMyIDwtIG11bHRpX2NyZlJlZyhkYXRhSW49c3RpbU5vdGljZURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkcywgbnRyZWU9bnRyZWUsIG10cnk9bXRyeSwgcGVybUltcENvbmRUaHJlcz1wZXJtSW1wQ29uZFRocmVzLCBucGVybT1ucGVybSwgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQoNCiMgcHJpbnQgbW9kZWwgcHJlZGljdGlvbiByZXN1bHRzDQpyZXN1bHRzT3V0U1FNczIkT09CX1JNU0UNCnJlc3VsdHNPdXRTUU1zMiRPT0JfTUFFDQpyZXN1bHRzT3V0U1FNczIkUnNxdWFyZWQNCg0KYGBgDQoNCmBgYHtyfQ0KDQojIHN0b3JlIHJlc3VsdHMNCnJlc05vdGljZUZpdFsnQWJzIFNRTXMgbm8gdG9uYWwgbG91ZCcsICdSTVNFJ10gPC0gcmVzdWx0c091dFNRTXMyJE9PQl9STVNFDQpyZXNOb3RpY2VGaXRbJ0FicyBTUU1zIG5vIHRvbmFsIGxvdWQnLCAnUk1TRSddIDwtIHJlc3VsdHNPdXRTUU1zMiRPT0JfTUFFDQpyZXNOb3RpY2VGaXRbJ0FicyBTUU1zIG5vIHRvbmFsIGxvdWQnLCAnUnNxdWFyZWQnXSA8LSByZXN1bHRzT3V0U1FNczIkUnNxdWFyZWQNCnJlc05vdGljZVBlcm1JbXAkQWJzU1FNczIgPC0gcmVzdWx0c091dFNRTXMyJGNvbmRpdGlvbmFsX3Blcm1pbXANCg0KYGBgDQoNCiMjIyMjIyBQbG90IHJlc3VsdHMNCg0KYGBge3IsIGZpZy53aWR0aD04LGZpZy5oZWlnaHQ9Mi40fQ0KcGFyKG1haT1jKDAsMywwLDApKQ0KDQojIHBsb3QgY29uZGl0aW9uYWwgaW1wb3J0YW5jZQ0KcmVzdWx0c091dFNRTXMyLmNvbmltcCA8LSBhcnJhbmdlKHJlc3VsdHNPdXRTUU1zMiRjb25kaXRpb25hbF9wZXJtaW1wLCBkZXNjKHJvd19udW1iZXIoKSkpDQoNCnBCYXIgPC0gZ2dwbG90KHJlc3VsdHNPdXRTUU1zMi5jb25pbXApICsgZ2VvbV9jb2woYWVzKHg9ZmFjdG9yKHJvd25hbWVzKHJlc3VsdHNPdXRTUU1zMi5jb25pbXApLCBsZXZlbHM9cm93bmFtZXMocmVzdWx0c091dFNRTXMyLmNvbmltcCkpLCB5PUNvbmRQZXJtSW1wKSwgZmlsbD1teWNvbG91cnNbN10sIHdpZHRoPTAuNSkgKyBsYWJzKHg9IlZhcmlhYmxlIiwgeT0iQ29uZGl0aW9uYWwgdmFyaWFibGUgcGVybXV0YXRpb24gaW1wb3J0YW5jZSAoJSBVQVMgbm90aWNlZCkiKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiksIHBhbmVsLmdyaWQ9ZWxlbWVudF9saW5lKGNvbG9yID0gcmdiKDIzNSwgMjM1LCAyMzUsIDEwMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksIGxpbmV3aWR0aCA9IDAuMjUsIGxpbmV0eXBlID0gMikpICsgY29vcmRfZmxpcCh5bGltPWMoLTEsIDgwMCkpDQpwQmFyDQoNCmlmIChzYXZlcGxvdHMpew0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QU5vdGljZUFic1NRTXNOb1RvbkxkQ29uUGVybWltcC5zdmciLCB3aWR0aD04LCBoZWlnaHQ9Mi40LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAic3ZnIikpDQogIHVubGluaygiUHRBTm90aWNlQWJzU1FNc05vVG9uTGRDb25QZXJtaW1wLnN2ZyIpDQogIA0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QU5vdGljZUFic1NRTXNOb1RvbkxkQ29uUGVybWltcC5wZGYiLCB3aWR0aD04LCBoZWlnaHQ9Mi40LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAicGRmIikpDQogIHVubGluaygiUHRBTm90aWNlQWJzU1FNc05vVG9uTGRDb25QZXJtaW1wLnBkZiIpDQp9DQoNCmBgYA0KDQojIyMgRGlmZmVyZW5jZSB2YXJpYWJsZXMNCg0KTmV4dCwgdGhlIGRpZmZlcmVuY2UgbWV0cmljcyBhcmUgYW5hbHlzZWQsIA0KDQojIyMjIFJlbW92ZSBhbWJpZW50IG9ubHkgc3RpbXVsaQ0KDQpIZXJlLCB0aGUgJ2FtYmllbnQgb25seScgc3RpbXVsaSBhcmUgcmVtb3ZlZCwgYXMgdGhlIGFuYWx5c2lzIGNhbm5vdCBoYW5kbGUgbWlzc2luZyB2YWx1ZXMgZm9yIGRCIG1ldHJpY3MuDQoNCmBgYHtyfQ0Kc3RpbU5vdGljZURhdGFBTnVtIDwtIHN0aW1Ob3RpY2VEYXRhQU51bVtjb21wbGV0ZS5jYXNlcyhzdGltTm90aWNlRGF0YUFOdW0pLF0NCnN0aW1Ob3RpY2VEYXRhQU51bSRVQVNMQWVxIDwtIGFzLm51bWVyaWMoc3RpbU5vdGljZURhdGFBTnVtJFVBU0xBZXEpDQpzdGltTm90aWNlRGF0YUFOdW0kU05SbGV2ZWwgPC0gYXMubnVtZXJpYyhzdGltTm90aWNlRGF0YUFOdW0kU05SbGV2ZWwpDQpgYGANCg0KIyMjIyBTZXQgdmFyaWFibGVzDQoNCmBgYHtyfQ0KDQppVmFycyA8LSBjKG5hbWVzKHN0aW1Ob3RpY2VEYXRhQU51bSlbd2hpY2goY29sbmFtZXMoc3RpbU5vdGljZURhdGFBTnVtKT09IkxBZXFMQUY5MGRpZmYiKToNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aGljaChjb2xuYW1lcyhzdGltTm90aWNlRGF0YUFOdW0pPT0iZEltcHVsc1NITTA1RXhNYXhMUiIpXSwgIlNOUmxldmVsIikNCmRWYXIgPC0gIk5vdGljZWRQY0ZpbHQiDQoNCnNlZWRzIDwtIGMoNTY4MzkyLCA0OTgsIDQwODksIDc4MTMyLCA3NDE4MDkpDQoNCmBgYA0KDQojIyMjIEh5cGVycGFyYW1ldGVyIHR1bmluZw0KDQpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTR9DQoNCnAgPC0gbXRyeVR1bmUoZGF0YUluPXN0aW1Ob3RpY2VEYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZD1zZWVkc1sxXSwNCiAgICAgICAgICAgICBudHJlZXM9bnRyZWVzLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCnANCg0KYGBgDQoNClNlbGVjdGVkIGh5cGVycGFyYW1ldGVycw0KDQpgYGB7cn0NCg0KbnRyZWUgPC0gMTUwMQ0KbXRyeSA8LSBhcy5pbnRlZ2VyKGxlbmd0aChpVmFycykvMy41KQ0KDQpgYGANCg0KDQojIyMjIFJ1biBtb2RlbA0KDQpUcmFpbiBwcmVsaW1pbmFyeSBtb2RlbA0KDQpgYGB7cn0NCg0KbnBlcm0gPC0gMzANCg0KcmVzdWx0c091dERpZmZzIDwtIGNyZlJlZyhkYXRhSW49c3RpbU5vdGljZURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkc1sxOjJdLCBudHJlZT1udHJlZSwgbXRyeT1tdHJ5LCBwZXJtSW1wQ29uZFRocmVzPXBlcm1JbXBDb25kVGhyZXMsIG5wZXJtPW5wZXJtLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCg0KIyBwcmludCBtb2RlbCBwcmVkaWN0aW9uIHJlc3VsdHMNCnJlc3VsdHNPdXREaWZmcyRPT0JfUk1TRQ0KcmVzdWx0c091dERpZmZzJE9PQl9NQUUNCnJlc3VsdHNPdXREaWZmcyRSc3F1YXJlZA0KDQpgYGANCg0KVHJhaW4gbXVsdGlwbGUgc2VlZHMgbW9kZWwNCg0KYGBge3J9DQoNCnJlc3VsdHNPdXREaWZmcyA8LSBtdWx0aV9jcmZSZWcoZGF0YUluPXN0aW1Ob3RpY2VEYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHMsIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dERpZmZzJE9PQl9STVNFDQpyZXN1bHRzT3V0RGlmZnMkT09CX01BRQ0KcmVzdWx0c091dERpZmZzJFJzcXVhcmVkDQoNCmBgYA0KDQpgYGB7cn0NCg0KIyBzdG9yZSByZXN1bHRzDQpyZXNOb3RpY2VGaXRbJ0RpZmYgdmFycycsICdSTVNFJ10gPC0gcmVzdWx0c091dERpZmZzJE9PQl9STVNFDQpyZXNOb3RpY2VGaXRbJ0RpZmYgdmFycycsICdNQUUnXSA8LSByZXN1bHRzT3V0RGlmZnMkT09CX01BRQ0KcmVzTm90aWNlRml0WydEaWZmIHZhcnMnLCAnUnNxdWFyZWQnXSA8LSByZXN1bHRzT3V0RGlmZnMkUnNxdWFyZWQNCnJlc05vdGljZVBlcm1JbXAkRGlmZlZhcnMgPC0gcmVzdWx0c091dERpZmZzJGNvbmRpdGlvbmFsX3Blcm1pbXANCg0KYGBgDQoNCiMjIyMgUGxvdCByZXN1bHRzDQoNCmBgYHtyLCBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTEwfQ0KcGFyKG1haT1jKDAsMywwLDApKQ0KDQojIHBsb3QgY29uZGl0aW9uYWwgaW1wb3J0YW5jZQ0KcmVzdWx0c091dERpZmZzLmNvbmltcCA8LSBhcnJhbmdlKHJlc3VsdHNPdXREaWZmcyRjb25kaXRpb25hbF9wZXJtaW1wLCBkZXNjKHJvd19udW1iZXIoKSkpDQoNCnBCYXIgPC0gZ2dwbG90KHJlc3VsdHNPdXREaWZmcy5jb25pbXApICsgZ2VvbV9jb2woYWVzKHg9ZmFjdG9yKHJvd25hbWVzKHJlc3VsdHNPdXREaWZmcy5jb25pbXApLCBsZXZlbHM9cm93bmFtZXMocmVzdWx0c091dERpZmZzLmNvbmltcCkpLCB5PUNvbmRQZXJtSW1wKSwgZmlsbD1teWNvbG91cnNbOF0sIHdpZHRoPTAuNSkgKyBsYWJzKHg9IlZhcmlhYmxlIiwgeT0iQ29uZGl0aW9uYWwgdmFyaWFibGUgcGVybXV0YXRpb24gaW1wb3J0YW5jZSAoJSBVQVMgbm90aWNlZCkiKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiksIHBhbmVsLmdyaWQ9ZWxlbWVudF9saW5lKGNvbG9yID0gcmdiKDIzNSwgMjM1LCAyMzUsIDEwMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksIGxpbmV3aWR0aCA9IDAuMjUsIGxpbmV0eXBlID0gMikpICsgY29vcmRfZmxpcCgpDQpwQmFyDQoNCmlmIChzYXZlcGxvdHMpew0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QU5vdGljZURpZmZWYXJzQ29uUGVybWltcC5zdmciLCB3aWR0aD04LCBoZWlnaHQ9MTAsIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJzdmciKSkNCiAgdW5saW5rKCJQdEFOb3RpY2VEaWZmVmFyc0NvblBlcm1pbXAuc3ZnIikNCiAgDQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBTm90aWNlRGlmZlZhcnNDb25QZXJtaW1wLnBkZiIsIHdpZHRoPTgsIGhlaWdodD0xMCwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInBkZiIpKQ0KICB1bmxpbmsoIlB0QU5vdGljZURpZmZWYXJzQ29uUGVybWltcC5wZGYiKQ0KfQ0KDQpgYGANCg0KYGBge3IsIGZpZy53aWR0aD04LGZpZy5oZWlnaHQ9OH0NCg0KIyBQbG90IG9ubHkgcG9zaXRpdmUgdmFsdWVzDQpyZXN1bHRzT3V0RGlmZnMuY29uaW1wUHR2IDwtIHJlc3VsdHNPdXREaWZmcy5jb25pbXAgfD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3duYW1lc190b19jb2x1bW4oJ01ldHJpYycpIHw+DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcl9pZihpcy5udW1lcmljLCBhbGxfdmFycyguID4gMCkpIHw+DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHVtbl90b19yb3duYW1lcygnTWV0cmljJykNCg0KcEJhciA8LSBnZ3Bsb3QocmVzdWx0c091dERpZmZzLmNvbmltcFB0dikgKyBnZW9tX2NvbChhZXMoeD1mYWN0b3Iocm93bmFtZXMocmVzdWx0c091dERpZmZzLmNvbmltcFB0diksIGxldmVscz1yb3duYW1lcyhyZXN1bHRzT3V0RGlmZnMuY29uaW1wUHR2KSksIHk9Q29uZFBlcm1JbXApLCBmaWxsPW15Y29sb3Vyc1s4XSwgd2lkdGg9MC41KSArIGxhYnMoeD0iVmFyaWFibGUiLCB5PSJDb25kaXRpb25hbCB2YXJpYWJsZSBwZXJtdXRhdGlvbiBpbXBvcnRhbmNlICglIFVBUyBub3RpY2VkKSIpICsgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2VyaWYiKSwgcGFuZWwuZ3JpZD1lbGVtZW50X2xpbmUoY29sb3IgPSByZ2IoMjM1LCAyMzUsIDIzNSwgMTAwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgbGluZXdpZHRoID0gMC4yNSwgbGluZXR5cGUgPSAyKSkgKyBjb29yZF9mbGlwKCkNCnBCYXINCg0KaWYgKHNhdmVwbG90cyl7DQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBTm90aWNlRGlmZlZhcnNDb25QZXJtaW1wUHR2LnN2ZyIsIHdpZHRoPTgsIGhlaWdodD04LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAic3ZnIikpDQogIHVubGluaygiUHRBTm90aWNlRGlmZlZhcnNDb25QZXJtaW1wUHR2LnN2ZyIpDQogIA0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QU5vdGljZURpZmZWYXJzQ29uUGVybWltcFB0di5wZGYiLCB3aWR0aD04LCBoZWlnaHQ9OCwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInBkZiIpKQ0KICB1bmxpbmsoIlB0QU5vdGljZURpZmZWYXJzQ29uUGVybWltcFB0di5wZGYiKQ0KfQ0KDQpgYGANCg0KU2VsZWN0ZWQgbWV0cmljDQoNCmBgYHtyfQ0KDQpkaWZmVmFyIDwtICJEZXRlY3QwcDVkQk1heE1heExSIg0KDQpgYGANCg0KIyMjIGRTUU0gYW5hbHlzaXMNCg0KVGhlIGFtYmllbnQtb25seSBzdGltdWxpIGFyZSBOT1QgcmVwbGFjZWQgaGVyZSwgYXMgdGhlIGRpZmZlcmVuY2UgYW5hbHlzaXMgaW5jbHVkZXMgZEIgbWV0cmljcy4NCg0KIyMjIyBJbmRpdmlkdWFsIFNRTXMNCg0KIyMjIyMgZFNoYXJwbmVzcw0KDQojIyMjIyMgU2V0IHZhcmlhYmxlcw0KDQpgYGB7cn0NCg0KaVZhcnMgPC0gYyhkaWZmVmFyLCAiZFNoYXJwQXVySVNPM1Bvd0F2Z01heExSIiwgImRTaGFycEF1cklTTzMwNUV4TWF4TFIiLCAiZFNoYXJwQXVyU0hNUG93QXZnTWF4TFIiLCAiZFNoYXJwQXVyU0hNMDVFeE1heExSIikNCmRWYXIgPC0gIk5vdGljZWRQY0ZpbHQiDQoNCnNlZWRzIDwtIGMoODQxOTQsIDkwNSwgOTI4MDU0LCA2MjUwOTEsIDU4MjAzMSkNCg0KYGBgDQoNCiMjIyMjIyBIeXBlcnBhcmFtZXRlciB0dW5pbmcNCg0KYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD00fQ0KDQpwIDwtIG10cnlUdW5lKGRhdGFJbj1zdGltTm90aWNlRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWQ9c2VlZHNbMV0sDQogICAgICAgICAgICAgbnRyZWVzPW50cmVlcywgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQpwDQoNCmBgYA0KDQpTZWxlY3RlZCBoeXBlcnBhcmFtZXRlcnMNCg0KYGBge3J9DQoNCm50cmVlIDwtIDI1MDENCm10cnkgPC0gYXMuaW50ZWdlcihsZW5ndGgoaVZhcnMpLzEuMjUpDQoNCmBgYA0KDQojIyMjIyMgUnVuIG1vZGVsDQoNClRyYWluIHByZWxpbWluYXJ5IG1vZGVsDQoNCmBgYHtyfQ0KDQpucGVybSA8LSA1DQoNCnJlc3VsdHNPdXRTaGFycCA8LSBjcmZSZWcoZGF0YUluPXN0aW1Ob3RpY2VEYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHNbMToyXSwgbnRyZWU9bnRyZWUsIG10cnk9bXRyeSwgcGVybUltcENvbmRUaHJlcz1wZXJtSW1wQ29uZFRocmVzLCBucGVybT1ucGVybSwgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQoNCiMgcHJpbnQgbW9kZWwgcHJlZGljdGlvbiByZXN1bHRzDQpyZXN1bHRzT3V0U2hhcnAkT09CX1JNU0UNCnJlc3VsdHNPdXRTaGFycCRPT0JfTUFFDQpyZXN1bHRzT3V0U2hhcnAkUnNxdWFyZWQNCg0KYGBgDQpUcmFpbiBtdWx0aXBsZSBzZWVkcyBtb2RlbA0KDQpgYGB7cn0NCg0KcmVzdWx0c091dFNoYXJwIDwtIG11bHRpX2NyZlJlZyhkYXRhSW49c3RpbU5vdGljZURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkcywgbnRyZWU9bnRyZWUsIG10cnk9bXRyeSwgcGVybUltcENvbmRUaHJlcz1wZXJtSW1wQ29uZFRocmVzLCBucGVybT1ucGVybSwgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQoNCiMgcHJpbnQgbW9kZWwgcHJlZGljdGlvbiByZXN1bHRzDQpyZXN1bHRzT3V0U2hhcnAkT09CX1JNU0UNCnJlc3VsdHNPdXRTaGFycCRPT0JfTUFFDQpyZXN1bHRzT3V0U2hhcnAkUnNxdWFyZWQNCg0KYGBgDQoNCg0KYGBge3J9DQojIHN0b3JlIHJlc3VsdHMNCnJlc05vdGljZUZpdFsnRGlmZiBzaGFycCcsICdSTVNFJ10gPC0gcmVzdWx0c091dFNoYXJwJE9PQl9STVNFDQpyZXNOb3RpY2VGaXRbJ0RpZmYgc2hhcnAnLCAnTUFFJ10gPC0gcmVzdWx0c091dFNoYXJwJE9PQl9NQUUNCnJlc05vdGljZUZpdFsnRGlmZiBzaGFycCcsICdSc3F1YXJlZCddIDwtIHJlc3VsdHNPdXRTaGFycCRSc3F1YXJlZA0KcmVzTm90aWNlUGVybUltcCREaWZmU2hhcnAgPC0gcmVzdWx0c091dFNoYXJwJGNvbmRpdGlvbmFsX3Blcm1pbXANCg0KYGBgDQoNCiMjIyMjIyBQbG90IHJlc3VsdHMNCg0KYGBge3IsIGZpZy53aWR0aD04LGZpZy5oZWlnaHQ9Mi42fQ0KcGFyKG1haT1jKDAsMywwLDApKQ0KDQojIHBsb3QgY29uZGl0aW9uYWwgaW1wb3J0YW5jZQ0KcmVzdWx0c091dFNoYXJwLmNvbmltcCA8LSBhcnJhbmdlKHJlc3VsdHNPdXRTaGFycCRjb25kaXRpb25hbF9wZXJtaW1wLCBkZXNjKHJvd19udW1iZXIoKSkpDQoNCnBCYXIgPC0gZ2dwbG90KHJlc3VsdHNPdXRTaGFycC5jb25pbXApICsgZ2VvbV9jb2woYWVzKHg9ZmFjdG9yKHJvd25hbWVzKHJlc3VsdHNPdXRTaGFycC5jb25pbXApLCBsZXZlbHM9cm93bmFtZXMocmVzdWx0c091dFNoYXJwLmNvbmltcCkpLCB5PUNvbmRQZXJtSW1wKSwgZmlsbD1teWNvbG91cnNbMl0sIHdpZHRoPTAuNSkgKyBsYWJzKHg9IlZhcmlhYmxlIiwgeT0iQ29uZGl0aW9uYWwgdmFyaWFibGUgcGVybXV0YXRpb24gaW1wb3J0YW5jZSAoJSBVQVMgbm90aWNlZCkiKSArIGdndGl0bGUoImRTaGFycG5lc3MiKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiksIHBhbmVsLmdyaWQ9ZWxlbWVudF9saW5lKGNvbG9yID0gcmdiKDIzNSwgMjM1LCAyMzUsIDEwMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksIGxpbmV3aWR0aCA9IDAuMjUsIGxpbmV0eXBlID0gMikpICsgY29vcmRfZmxpcCgpDQpwQmFyDQoNCmlmIChzYXZlcGxvdHMpew0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QU5vdGljZWRTaGFycENvblBlcm1pbXAuc3ZnIiwgd2lkdGg9OCwgaGVpZ2h0PTIuNiwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInN2ZyIpKQ0KICB1bmxpbmsoIlB0QU5vdGljZWRTaGFycENvblBlcm1pbXAuc3ZnIikNCiAgDQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBTm90aWNlZFNoYXJwQ29uUGVybWltcC5wZGYiLCB3aWR0aD04LCBoZWlnaHQ9Mi42LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAicGRmIikpDQogIHVubGluaygiUHRBTm90aWNlZFNoYXJwQ29uUGVybWltcC5wZGYiKQ0KfQ0KDQoNCmBgYA0KDQpTZWxlY3RlZCBtZXRyaWMNCg0KYGBge3J9DQoNCnNoYXJwVmFyIDwtICJkU2hhcnBBdXJJU08zMDVFeE1heExSIg0KDQpgYGANCg0KIyMjIyMgZFRvbmFsIGxvdWRuZXNzIGFuZCBkdG9uYWxpdHkNCg0KIyMjIyMjIFNldCB2YXJpYWJsZXMNCg0KYGBge3J9DQoNCmlWYXJzIDwtIGMoZGlmZlZhciwgImRUb25hbEVDTUFBdmdNYXhMUiIsICJkVG9uYWxTSE1JbnQwNUV4TWF4TFIiLCAiZFRvbmFsU0hNSW50QXZnTWF4TFIiLCAiZFRvbmFsRUNNQTA1RXhNYXhMUiIsICJkVG9uTGRFQ01BUG93QXZnQmluIiwgImRUb25MZEVDTUEwNUV4QmluIikNCmRWYXIgPC0gIk5vdGljZWRQY0ZpbHQiDQoNCnNlZWRzIDwtIGMoNTYxNjg0LCAxMDQ3OTgsIDE1MzYsIDQ4LCA0ODU2MSkNCg0KYGBgDQoNCiMjIyMjIyBIeXBlcnBhcmFtZXRlciB0dW5pbmcNCg0KYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD00fQ0KDQpwIDwtIG10cnlUdW5lKGRhdGFJbj1zdGltTm90aWNlRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWQ9c2VlZHNbMV0sDQogICAgICAgICAgICAgbnRyZWVzPW50cmVlcywgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQpwDQoNCmBgYA0KDQpTZWxlY3RlZCBoeXBlcnBhcmFtZXRlcnMNCg0KYGBge3J9DQoNCm50cmVlIDwtMTUwMQ0KbXRyeSA8LSBhcy5pbnRlZ2VyKGxlbmd0aChpVmFycykvMS4yNSkNCg0KYGBgDQoNCg0KIyMjIyMjIFJ1biBtb2RlbA0KDQpUcmFpbiBwcmVsaW1pbmFyeSBtb2RlbA0KDQpgYGB7cn0NCiMgVG9uYWxpdHkgd2l0aCB0b25hbCBsb3VkbmVzcw0KDQpucGVybSA8LSA1DQoNCnJlc3VsdHNPdXRUb25hbDEgPC0gY3JmUmVnKGRhdGFJbj1zdGltTm90aWNlRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzWzE6Ml0sIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dFRvbmFsMSRPT0JfUk1TRQ0KcmVzdWx0c091dFRvbmFsMSRPT0JfTUFFDQpyZXN1bHRzT3V0VG9uYWwxJFJzcXVhcmVkDQpgYGANCg0KVHJhaW4gbXVsdGlwbGUgc2VlZHMgbW9kZWwNCg0KYGBge3J9DQojIFRvbmFsaXR5IHdpdGggdG9uYWwgbG91ZG5lc3MNCg0KcmVzdWx0c091dFRvbmFsMSA8LSBtdWx0aV9jcmZSZWcoZGF0YUluPXN0aW1Ob3RpY2VEYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHMsIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dFRvbmFsMSRPT0JfUk1TRQ0KcmVzdWx0c091dFRvbmFsMSRPT0JfTUFFDQpyZXN1bHRzT3V0VG9uYWwxJFJzcXVhcmVkDQoNCmBgYA0KDQpgYGB7cn0NCiMgc3RvcmUgcmVzdWx0cw0KcmVzTm90aWNlRml0WydEaWZmIHRvbmFsIGluYyBsb3VkJywgJ1JNU0UnXSA8LSByZXN1bHRzT3V0VG9uYWwxJE9PQl9STVNFDQpyZXNOb3RpY2VGaXRbJ0RpZmYgdG9uYWwgaW5jIGxvdWQnLCAnTUFFJ10gPC0gcmVzdWx0c091dFRvbmFsMSRPT0JfTUFFDQpyZXNOb3RpY2VGaXRbJ0RpZmYgdG9uYWwgaW5jIGxvdWQnLCAnUnNxdWFyZWQnXSA8LSByZXN1bHRzT3V0VG9uYWwxJFJzcXVhcmVkDQpyZXNOb3RpY2VQZXJtSW1wJERpZmZUb25hbDEgPC0gcmVzdWx0c091dFRvbmFsMSRjb25kaXRpb25hbF9wZXJtaW1wDQoNCmBgYA0KDQojIyMjIyMgUGxvdCByZXN1bHRzDQoNCmBgYHtyLCBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTIuNn0NCg0KcGFyKG1haT1jKDAsMywwLDApKQ0KDQojIHBsb3QgY29uZGl0aW9uYWwgaW1wb3J0YW5jZQ0KcmVzdWx0c091dFRvbmFsMS5jb25pbXAgPC0gYXJyYW5nZShyZXN1bHRzT3V0VG9uYWwxJGNvbmRpdGlvbmFsX3Blcm1pbXAsIGRlc2Mocm93X251bWJlcigpKSkNCg0KcEJhciA8LSBnZ3Bsb3QocmVzdWx0c091dFRvbmFsMS5jb25pbXApICsgZ2VvbV9jb2woYWVzKHg9ZmFjdG9yKHJvd25hbWVzKHJlc3VsdHNPdXRUb25hbDEuY29uaW1wKSwgbGV2ZWxzPXJvd25hbWVzKHJlc3VsdHNPdXRUb25hbDEuY29uaW1wKSksIHk9Q29uZFBlcm1JbXApLCBmaWxsPW15Y29sb3Vyc1szXSwgd2lkdGg9MC41KSArIGxhYnMoeD0iVmFyaWFibGUiLCB5PSJDb25kaXRpb25hbCB2YXJpYWJsZSBwZXJtdXRhdGlvbiBpbXBvcnRhbmNlICglIFVBUyBub3RpY2VkKSIpICsgZ2d0aXRsZSgiZFRvbmFsaXR5IGluYy4gZHRvbmFsIGxvdWRuZXNzIikgKyB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIpLCBwYW5lbC5ncmlkPWVsZW1lbnRfbGluZShjb2xvciA9IHJnYigyMzUsIDIzNSwgMjM1LCAxMDAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCBsaW5ld2lkdGggPSAwLjI1LCBsaW5ldHlwZSA9IDIpKSArIGNvb3JkX2ZsaXAoeWxpbT1jKDAsIDEyMDApKQ0KcEJhcg0KDQppZiAoc2F2ZXBsb3RzKXsNCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFOb3RpY2VkVG9uYWxMZENvblBlcm1pbXAuc3ZnIiwgd2lkdGg9OCwgaGVpZ2h0PTIuNiwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInN2ZyIpKQ0KICB1bmxpbmsoIlB0QU5vdGljZWRUb25hbExkQ29uUGVybWltcC5zdmciKQ0KICANCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFOb3RpY2VkVG9uYWxMZENvblBlcm1pbXAucGRmIiwgd2lkdGg9OCwgaGVpZ2h0PTIuNiwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInBkZiIpKQ0KICB1bmxpbmsoIlB0QU5vdGljZWRUb25hbExkQ29uUGVybWltcC5wZGYiKQ0KfQ0KDQpgYGANCg0KU2VsZWN0ZWQgbWV0cmljDQoNCmBgYHtyfQ0KDQp0b25MZFZhciA8LSAiZFRvbkxkRUNNQVBvd0F2Z0JpbiINCg0KYGBgDQoNCg0KIyMjIyMgZFRvbmFsaXR5IHdpdGhvdXQgZHRvbmFsIGxvdWRuZXNzDQoNCiMjIyMjIyBTZXQgdmFyaWFibGVzDQoNCmBgYHtyfQ0KDQppVmFycyA8LSBjKGRpZmZWYXIsICJkVG9uYWxFQ01BQXZnTWF4TFIiLCAiZFRvbmFsU0hNSW50MDVFeE1heExSIiwgImRUb25hbFNITUludEF2Z01heExSIiwgImRUb25hbEVDTUEwNUV4TWF4TFIiKQ0KZFZhciA8LSAiTm90aWNlZFBjRmlsdCINCg0Kc2VlZHMgPC0gYyg0MTA4NjUsIDI5NTQsIDcwODEyLCAyMDMsIDc5ODQpDQoNCmBgYA0KDQojIyMjIyMgSHlwZXJwYXJhbWV0ZXIgdHVuaW5nDQoNCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NH0NCg0KcCA8LSBtdHJ5VHVuZShkYXRhSW49c3RpbU5vdGljZURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkPXNlZWRzWzFdLA0KICAgICAgICAgICAgIG50cmVlcz1udHJlZXMsIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KcA0KDQpgYGANCg0KU2VsZWN0ZWQgaHlwZXJwYXJhbWV0ZXJzDQoNCmBgYHtyfQ0KDQpudHJlZSA8LSAxNTAxDQptdHJ5IDwtIGFzLmludGVnZXIobGVuZ3RoKGlWYXJzKS8xLjI1KQ0KDQpgYGANCg0KDQojIyMjIyMgUnVuIG1vZGVsDQoNClRyYWluIHByZWxpbWluYXJ5IG1vZGVsDQoNCmBgYHtyfQ0KIyBUb25hbGl0eQ0KDQpucGVybSA8LSA1DQoNCnJlc3VsdHNPdXRUb25hbDIgPC0gY3JmUmVnKGRhdGFJbj1zdGltTm90aWNlRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzWzE6Ml0sIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dFRvbmFsMiRPT0JfUk1TRQ0KcmVzdWx0c091dFRvbmFsMiRPT0JfTUFFDQpyZXN1bHRzT3V0VG9uYWwyJFJzcXVhcmVkDQoNCmBgYA0KDQpUcmFpbiBtdWx0aXBsZSBzZWVkcyBtb2RlbA0KDQpgYGB7cn0NCiMgVG9uYWxpdHkNCg0KcmVzdWx0c091dFRvbmFsMiA8LSBtdWx0aV9jcmZSZWcoZGF0YUluPXN0aW1Ob3RpY2VEYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHMsIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dFRvbmFsMiRPT0JfUk1TRQ0KcmVzdWx0c091dFRvbmFsMiRPT0JfTUFFDQpyZXN1bHRzT3V0VG9uYWwyJFJzcXVhcmVkDQoNCmBgYA0KDQoNCmBgYHtyfQ0KDQojIHN0b3JlIHJlc3VsdHMNCnJlc05vdGljZUZpdFsnRGlmZiB0b25hbCBubyBsb3VkJywgJ1JNU0UnXSA8LSByZXN1bHRzT3V0VG9uYWwyJE9PQl9STVNFDQpyZXNOb3RpY2VGaXRbJ0RpZmYgdG9uYWwgbm8gbG91ZCcsICdNQUUnXSA8LSByZXN1bHRzT3V0VG9uYWwyJE9PQl9NQUUNCnJlc05vdGljZUZpdFsnRGlmZiB0b25hbCBubyBsb3VkJywgJ1JzcXVhcmVkJ10gPC0gcmVzdWx0c091dFRvbmFsMiRSc3F1YXJlZA0KcmVzTm90aWNlUGVybUltcCREaWZmVG9uYWwyIDwtIHJlc3VsdHNPdXRUb25hbDIkY29uZGl0aW9uYWxfcGVybWltcA0KDQpgYGANCg0KIyMjIyMjIFBsb3QgcmVzdWx0cw0KDQpgYGB7ciwgZmlnLndpZHRoPTgsZmlnLmhlaWdodD0yfQ0KcGFyKG1haT1jKDAsMywwLDApKQ0KDQojIHBsb3QgY29uZGl0aW9uYWwgaW1wb3J0YW5jZQ0KcmVzdWx0c091dFRvbmFsMi5jb25pbXAgPC0gYXJyYW5nZShyZXN1bHRzT3V0VG9uYWwyJGNvbmRpdGlvbmFsX3Blcm1pbXAsIGRlc2Mocm93X251bWJlcigpKSkNCg0KcEJhciA8LSBnZ3Bsb3QocmVzdWx0c091dFRvbmFsMi5jb25pbXApICsgZ2VvbV9jb2woYWVzKHg9ZmFjdG9yKHJvd25hbWVzKHJlc3VsdHNPdXRUb25hbDIuY29uaW1wKSwgbGV2ZWxzPXJvd25hbWVzKHJlc3VsdHNPdXRUb25hbDIuY29uaW1wKSksIHk9Q29uZFBlcm1JbXApLCBmaWxsPW15Y29sb3Vyc1szXSwgd2lkdGg9MC41KSArIGxhYnMoeD0iVmFyaWFibGUiLCB5PSJDb25kaXRpb25hbCB2YXJpYWJsZSBwZXJtdXRhdGlvbiBpbXBvcnRhbmNlICglIFVBUyBub3RpY2VkKSIpICsgZ2d0aXRsZSgiZFRvbmFsaXR5IHcvbyB0b25hbCBsb3VkbmVzcyIpICsgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2VyaWYiKSwgcGFuZWwuZ3JpZD1lbGVtZW50X2xpbmUoY29sb3IgPSByZ2IoMjM1LCAyMzUsIDIzNSwgMTAwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgbGluZXdpZHRoID0gMC4yNSwgbGluZXR5cGUgPSAyKSkgKyBjb29yZF9mbGlwKHlsaW09YygwLCAxMjAwKSkNCnBCYXINCg0KaWYgKHNhdmVwbG90cyl7DQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBTm90aWNlZFRvbmFsQ29uUGVybWltcC5zdmciLCB3aWR0aD04LCBoZWlnaHQ9MiwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInN2ZyIpKQ0KICB1bmxpbmsoIlB0QU5vdGljZWRUb25hbENvblBlcm1pbXAuc3ZnIikNCiAgDQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBTm90aWNlZFRvbmFsQ29uUGVybWltcC5wZGYiLCB3aWR0aD04LCBoZWlnaHQ9MiwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInBkZiIpKQ0KICB1bmxpbmsoIlB0QU5vdGljZWRUb25hbENvblBlcm1pbXAucGRmIikNCn0NCg0KDQpgYGANCg0KU2VsZWN0ZWQgbWV0cmljDQoNCmBgYHtyfQ0KDQp0b25hbFZhciA8LSAiZFRvbmFsRUNNQUF2Z01heExSIg0KDQpgYGANCg0KIyMjIyMgZEZsdWN0dWF0aW9uIHN0cmVuZ3RoDQoNCiMjIyMjIyBTZXQgdmFyaWFibGVzDQoNCmBgYHtyfQ0KDQojIEZsdWN0dWF0aW9uIHN0cmVuZ3RoDQppVmFycyA8LSBjKGRpZmZWYXIsICJkRmx1Y3RTSE0xMEV4QmluIiwgImRGbHVjdFNITTA1RXhCaW4iLCAiZEZsdWN0T1YxMEV4TWF4TFIiLCAiZEZsdWN0T1YwNUV4TWF4TFIiKQ0KZFZhciA8LSAiTm90aWNlZFBjRmlsdCINCg0Kc2VlZHMgPC0gYyg0MTg2NTcsIDg0LCAxNjMwLCAxODY1OSwgMzY4NykNCg0KYGBgDQoNCiMjIyMjIyBIeXBlcnBhcmFtZXRlciB0dW5pbmcNCg0KYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD00fQ0KDQpwIDwtIG10cnlUdW5lKGRhdGFJbj1zdGltTm90aWNlRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWQ9c2VlZHNbMV0sDQogICAgICAgICAgICAgbnRyZWVzPW50cmVlcywgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQpwDQoNCmBgYA0KDQpTZWxlY3RlZCBoeXBlcnBhcmFtZXRlcnMNCg0KYGBge3J9DQoNCm50cmVlIDwtIDE1MDENCm10cnkgPC0gYXMuaW50ZWdlcihsZW5ndGgoaVZhcnMpLzEuMjUpDQoNCmBgYA0KDQoNCiMjIyMjIyBSdW4gbW9kZWwNCg0KVHJhaW4gcHJlbGltaW5hcnkgbW9kZWwNCg0KYGBge3J9DQoNCm5wZXJtIDwtIDUNCg0KcmVzdWx0c091dEZsdWN0IDwtIGNyZlJlZyhkYXRhSW49c3RpbU5vdGljZURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkc1sxOjJdLCBudHJlZT1udHJlZSwgbXRyeT1tdHJ5LCBwZXJtSW1wQ29uZFRocmVzPXBlcm1JbXBDb25kVGhyZXMsIG5wZXJtPW5wZXJtLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCg0KIyBwcmludCBtb2RlbCBwcmVkaWN0aW9uIHJlc3VsdHMNCnJlc3VsdHNPdXRGbHVjdCRPT0JfUk1TRQ0KcmVzdWx0c091dEZsdWN0JE9PQl9NQUUNCnJlc3VsdHNPdXRGbHVjdCRSc3F1YXJlZA0KDQpgYGANClRyYWluIG11bHRpcGxlIHNlZWRzIG1vZGVsDQoNCmBgYHtyfQ0KDQpyZXN1bHRzT3V0Rmx1Y3QgPC0gbXVsdGlfY3JmUmVnKGRhdGFJbj1zdGltTm90aWNlRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzLCBudHJlZT1udHJlZSwgbXRyeT1tdHJ5LCBwZXJtSW1wQ29uZFRocmVzPXBlcm1JbXBDb25kVGhyZXMsIG5wZXJtPW5wZXJtLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCg0KIyBwcmludCBtb2RlbCBwcmVkaWN0aW9uIHJlc3VsdHMNCnJlc3VsdHNPdXRGbHVjdCRPT0JfUk1TRQ0KcmVzdWx0c091dEZsdWN0JE9PQl9NQUUNCnJlc3VsdHNPdXRGbHVjdCRSc3F1YXJlZA0KDQpgYGANCg0KDQpgYGB7cn0NCg0KIyBzdG9yZSByZXN1bHRzDQpyZXNOb3RpY2VGaXRbJ0RpZmYgZmx1Y3QnLCAnUk1TRSddIDwtIHJlc3VsdHNPdXRGbHVjdCRPT0JfUk1TRQ0KcmVzTm90aWNlRml0WydEaWZmIGZsdWN0JywgJ01BRSddIDwtIHJlc3VsdHNPdXRGbHVjdCRPT0JfTUFFDQpyZXNOb3RpY2VGaXRbJ0RpZmYgZmx1Y3QnLCAnUnNxdWFyZWQnXSA8LSByZXN1bHRzT3V0Rmx1Y3QkUnNxdWFyZWQNCnJlc05vdGljZVBlcm1JbXAkRGlmZkZsdWN0IDwtIHJlc3VsdHNPdXRGbHVjdCRjb25kaXRpb25hbF9wZXJtaW1wDQoNCmBgYA0KDQojIyMjIyMgUGxvdCByZXN1bHRzDQoNCmBgYHtyLCBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTJ9DQpwYXIobWFpPWMoMCwzLDAsMCkpDQoNCiMgcGxvdCBjb25kaXRpb25hbCBpbXBvcnRhbmNlDQpyZXN1bHRzT3V0Rmx1Y3QuY29uaW1wIDwtIGFycmFuZ2UocmVzdWx0c091dEZsdWN0JGNvbmRpdGlvbmFsX3Blcm1pbXAsIGRlc2Mocm93X251bWJlcigpKSkNCg0KcEJhciA8LSBnZ3Bsb3QocmVzdWx0c091dEZsdWN0LmNvbmltcCkgKyBnZW9tX2NvbChhZXMoeD1mYWN0b3Iocm93bmFtZXMocmVzdWx0c091dEZsdWN0LmNvbmltcCksIGxldmVscz1yb3duYW1lcyhyZXN1bHRzT3V0Rmx1Y3QuY29uaW1wKSksIHk9Q29uZFBlcm1JbXApLCBmaWxsPW15Y29sb3Vyc1s0XSwgd2lkdGg9MC41KSArIGxhYnMoeD0iVmFyaWFibGUiLCB5PSJDb25kaXRpb25hbCB2YXJpYWJsZSBwZXJtdXRhdGlvbiBpbXBvcnRhbmNlICglIFVBUyBub3RpY2VkKSIpICsgZ2d0aXRsZSgiZEZsdWN0dWF0aW9uIHN0cmVuZ3RoIikgKyB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIpLCBwYW5lbC5ncmlkPWVsZW1lbnRfbGluZShjb2xvciA9IHJnYigyMzUsIDIzNSwgMjM1LCAxMDAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCBsaW5ld2lkdGggPSAwLjI1LCBsaW5ldHlwZSA9IDIpKSArIGNvb3JkX2ZsaXAoKQ0KcEJhcg0KDQppZiAoc2F2ZXBsb3RzKXsNCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFOb3RpY2VkRmx1Y3RDb25QZXJtaW1wLnN2ZyIsIHdpZHRoPTgsIGhlaWdodD0yLCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAic3ZnIikpDQogIHVubGluaygiUHRBTm90aWNlRmx1Y3RDb25QZXJtaW1wLnN2ZyIpDQogIA0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QU5vdGljZWRGbHVjdENvblBlcm1pbXAucGRmIiwgd2lkdGg9OCwgaGVpZ2h0PTIsIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJwZGYiKSkNCiAgdW5saW5rKCJQdEFOb3RpY2VGbHVjdENvblBlcm1pbXAucGRmIikNCn0NCg0KYGBgDQoNClNlbGVjdGVkIG1ldHJpYw0KDQpgYGB7cn0NCg0KZmx1Y3RWYXIgPC0gImRGbHVjdFNITTA1RXhCaW4iDQoNCmBgYA0KDQojIyMjIyBkUm91Z2huZXNzDQoNCiMjIyMjIyBTZXQgdmFyaWFibGVzDQoNCmBgYHtyfQ0KDQojIFJvdWdobmVzcw0KaVZhcnMgPC0gYyhkaWZmVmFyLCAiZFJvdWdoRUNNQTEwRXhCaW4iLCAiZFJvdWdoRUNNQTA1RXhCaW4iLCAiZFJvdWdoRloxMEV4TWF4TFIiLCAiZFJvdWdoRlowNUV4TWF4TFIiKQ0KZFZhciA8LSAiTm90aWNlZFBjRmlsdCINCg0Kc2VlZHMgPC0gYyg2OTg1MSwgODUxMDksIDQxMDk4NiwgMTU2MywgODk2KQ0KDQpgYGANCg0KIyMjIyMjIEh5cGVycGFyYW1ldGVyIHR1bmluZw0KDQpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTR9DQoNCnAgPC0gbXRyeVR1bmUoZGF0YUluPXN0aW1Ob3RpY2VEYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZD1zZWVkc1sxXSwNCiAgICAgICAgICAgICBudHJlZXM9bnRyZWVzLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCnANCg0KYGBgDQoNClNlbGVjdGVkIGh5cGVycGFyYW1ldGVycw0KDQpgYGB7cn0NCg0KbnRyZWUgPC0gMjUwMQ0KbXRyeSA8LSBhcy5pbnRlZ2VyKGxlbmd0aChpVmFycykvMS4yNSkNCg0KYGBgDQoNCg0KIyMjIyMjIFJ1biBtb2RlbA0KDQpUcmFpbiBwcmVsaW1pbmFyeSBtb2RlbA0KDQpgYGB7cn0NCg0KbnBlcm0gPC0gNQ0KDQpyZXN1bHRzT3V0Um91Z2ggPC0gY3JmUmVnKGRhdGFJbj1zdGltTm90aWNlRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzWzE6Ml0sIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dFJvdWdoJE9PQl9STVNFDQpyZXN1bHRzT3V0Um91Z2gkT09CX01BRQ0KcmVzdWx0c091dFJvdWdoJFJzcXVhcmVkDQoNCmBgYA0KDQpUcmFpbiBtdWx0aXBsZSBzZWVkcyBtb2RlbA0KDQpgYGB7cn0NCg0KcmVzdWx0c091dFJvdWdoIDwtIG11bHRpX2NyZlJlZyhkYXRhSW49c3RpbU5vdGljZURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkcywgbnRyZWU9bnRyZWUsIG10cnk9bXRyeSwgcGVybUltcENvbmRUaHJlcz1wZXJtSW1wQ29uZFRocmVzLCBucGVybT1ucGVybSwgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQoNCiMgcHJpbnQgbW9kZWwgcHJlZGljdGlvbiByZXN1bHRzDQpyZXN1bHRzT3V0Um91Z2gkT09CX1JNU0UNCnJlc3VsdHNPdXRSb3VnaCRPT0JfTUFFDQpyZXN1bHRzT3V0Um91Z2gkUnNxdWFyZWQNCg0KYGBgDQoNCmBgYHtyfQ0KIyBzdG9yZSByZXN1bHRzDQpyZXNOb3RpY2VGaXRbJ0RpZmYgcm91Z2gnLCAnUk1TRSddIDwtIHJlc3VsdHNPdXRSb3VnaCRPT0JfUk1TRQ0KcmVzTm90aWNlRml0WydEaWZmIHJvdWdoJywgJ01BRSddIDwtIHJlc3VsdHNPdXRSb3VnaCRPT0JfTUFFDQpyZXNOb3RpY2VGaXRbJ0RpZmYgcm91Z2gnLCAnUnNxdWFyZWQnXSA8LSByZXN1bHRzT3V0Um91Z2gkUnNxdWFyZWQNCnJlc05vdGljZVBlcm1JbXAkRGlmZlJvdWdoIDwtIHJlc3VsdHNPdXRSb3VnaCRjb25kaXRpb25hbF9wZXJtaW1wDQoNCmBgYA0KDQojIyMjIyMgUGxvdCByZXN1bHRzDQoNCmBgYHtyLCBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTJ9DQpwYXIobWFpPWMoMCwzLDAsMCkpDQoNCiMgcGxvdCBjb25kaXRpb25hbCBpbXBvcnRhbmNlDQpyZXN1bHRzT3V0Um91Z2guY29uaW1wIDwtIGFycmFuZ2UocmVzdWx0c091dFJvdWdoJGNvbmRpdGlvbmFsX3Blcm1pbXAsIGRlc2Mocm93X251bWJlcigpKSkNCg0KcEJhciA8LSBnZ3Bsb3QocmVzdWx0c091dFJvdWdoLmNvbmltcCkgKyBnZW9tX2NvbChhZXMoeD1mYWN0b3Iocm93bmFtZXMocmVzdWx0c091dFJvdWdoLmNvbmltcCksIGxldmVscz1yb3duYW1lcyhyZXN1bHRzT3V0Um91Z2guY29uaW1wKSksIHk9Q29uZFBlcm1JbXApLCBmaWxsPW15Y29sb3Vyc1s1XSwgd2lkdGg9MC41KSArIGxhYnMoeD0iVmFyaWFibGUiLCB5PSJDb25kaXRpb25hbCB2YXJpYWJsZSBwZXJtdXRhdGlvbiBpbXBvcnRhbmNlICglIFVBUyBub3RpY2VkKSIpICsgZ2d0aXRsZSgiZFJvdWdobmVzcyIpICsgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2VyaWYiKSwgcGFuZWwuZ3JpZD1lbGVtZW50X2xpbmUoY29sb3IgPSByZ2IoMjM1LCAyMzUsIDIzNSwgMTAwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgbGluZXdpZHRoID0gMC4yNSwgbGluZXR5cGUgPSAyKSkgKyBjb29yZF9mbGlwKCkNCnBCYXINCg0KaWYgKHNhdmVwbG90cyl7DQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBTm90aWNlZFJvdWdoQ29uUGVybWltcC5zdmciLCB3aWR0aD04LCBoZWlnaHQ9MiwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInN2ZyIpKQ0KICB1bmxpbmsoIlB0QU5vdGljZWRSb3VnaENvblBlcm1pbXAuc3ZnIikNCiAgDQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBTm90aWNlZFJvdWdoQ29uUGVybWltcC5wZGYiLCB3aWR0aD04LCBoZWlnaHQ9MiwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInBkZiIpKQ0KICB1bmxpbmsoIlB0QU5vdGljZWRSb3VnaENvblBlcm1pbXAucGRmIikNCn0NCg0KDQpgYGANCg0KU2VsZWN0ZWQgbWV0cmljDQoNCmBgYHtyfQ0KDQpyb3VnaFZhciA8LSAiZFJvdWdoRUNNQTA1RXhCaW4iDQoNCmBgYA0KDQojIyMjIyBkSW1wdWxzaXZlbmVzcw0KDQojIyMjIyMgU2V0IHZhcmlhYmxlcw0KDQpgYGB7cn0NCiMgSW1wdWxzaXZlbmVzcw0KaVZhcnMgPC0gYyhkaWZmVmFyLCAiZEltcHVsc1NITUF2Z01heExSIiwgImRJbXB1bHNTSE0wNUV4TWF4TFIiLCAiZEltcHVsc1NITVBvd0F2Z01heExSIikNCmRWYXIgPC0gIk5vdGljZWRQY0ZpbHQiDQoNCnNlZWRzIDwtIGMoNDE4NjU5LCA3ODA1LCAzODQ3NSwgNjU4MzQsIDE2NTMpDQoNCmBgYA0KDQojIyMjIyMgSHlwZXJwYXJhbWV0ZXIgdHVuaW5nDQoNCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NH0NCg0KcCA8LSBtdHJ5VHVuZShkYXRhSW49c3RpbU5vdGljZURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkPXNlZWRzWzFdLA0KICAgICAgICAgICAgIG50cmVlcz1udHJlZXMsIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KcA0KDQpgYGANCg0KU2VsZWN0ZWQgaHlwZXJwYXJhbWV0ZXJzDQoNCmBgYHtyfQ0KDQpudHJlZSA8LSAyNTENCm10cnkgPC0gYXMuaW50ZWdlcihsZW5ndGgoaVZhcnMpLzEuMjUpDQoNCmBgYA0KDQojIyMjIyMgUnVuIG1vZGVsDQoNClRyYWluIHByZWxpbWluYXJ5IG1vZGVsDQoNCmBgYHtyfQ0KDQpucGVybSA8LSA1DQoNCnJlc3VsdHNPdXRJbXB1bHMgPC0gY3JmUmVnKGRhdGFJbj1zdGltTm90aWNlRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzWzE6Ml0sIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dEltcHVscyRPT0JfUk1TRQ0KcmVzdWx0c091dEltcHVscyRPT0JfTUFFDQpyZXN1bHRzT3V0SW1wdWxzJFJzcXVhcmVkDQoNCmBgYA0KDQpUcmFpbiBtdWx0aXBsZSBzZWVkcyBtb2RlbA0KDQpgYGB7cn0NCg0KcmVzdWx0c091dEltcHVscyA8LSBtdWx0aV9jcmZSZWcoZGF0YUluPXN0aW1Ob3RpY2VEYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHMsIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dEltcHVscyRPT0JfUk1TRQ0KcmVzdWx0c091dEltcHVscyRPT0JfTUFFDQpyZXN1bHRzT3V0SW1wdWxzJFJzcXVhcmVkDQoNCmBgYA0KDQpgYGB7cn0NCg0KIyBzdG9yZSByZXN1bHRzDQpyZXNOb3RpY2VGaXRbJ0RpZmYgaW1wdWxzJywgJ1JNU0UnXSA8LSByZXN1bHRzT3V0SW1wdWxzJE9PQl9STVNFDQpyZXNOb3RpY2VGaXRbJ0RpZmYgaW1wdWxzJywgJ01BRSddIDwtIHJlc3VsdHNPdXRJbXB1bHMkT09CX01BRQ0KcmVzTm90aWNlRml0WydEaWZmIGltcHVscycsICdSc3F1YXJlZCddIDwtIHJlc3VsdHNPdXRJbXB1bHMkUnNxdWFyZWQNCnJlc05vdGljZVBlcm1JbXAkRGlmZkltcHVscyA8LSByZXN1bHRzT3V0SW1wdWxzJGNvbmRpdGlvbmFsX3Blcm1pbXANCg0KYGBgDQoNCiMjIyMjIyBQbG90IHJlc3VsdHMNCg0KYGBge3IsIGZpZy53aWR0aD04LGZpZy5oZWlnaHQ9Mn0NCnBhcihtYWk9YygwLDMsMCwwKSkNCg0KIyBwbG90IGNvbmRpdGlvbmFsIGltcG9ydGFuY2UNCnJlc3VsdHNPdXRJbXB1bHMuY29uaW1wIDwtIGFycmFuZ2UocmVzdWx0c091dEltcHVscyRjb25kaXRpb25hbF9wZXJtaW1wLCBkZXNjKHJvd19udW1iZXIoKSkpDQoNCnBCYXIgPC0gZ2dwbG90KHJlc3VsdHNPdXRJbXB1bHMuY29uaW1wKSArIGdlb21fY29sKGFlcyh4PWZhY3Rvcihyb3duYW1lcyhyZXN1bHRzT3V0SW1wdWxzLmNvbmltcCksIGxldmVscz1yb3duYW1lcyhyZXN1bHRzT3V0SW1wdWxzLmNvbmltcCkpLCB5PUNvbmRQZXJtSW1wKSwgZmlsbD1teWNvbG91cnNbNl0sIHdpZHRoPTAuNSkgKyBsYWJzKHg9IlZhcmlhYmxlIiwgeT0iQ29uZGl0aW9uYWwgdmFyaWFibGUgcGVybXV0YXRpb24gaW1wb3J0YW5jZSAoJSBVQVMgbm90aWNlZCkiKSArIGdndGl0bGUoImRJbXB1bHNpdmVuZXNzIikgKyB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIpLCBwYW5lbC5ncmlkPWVsZW1lbnRfbGluZShjb2xvciA9IHJnYigyMzUsIDIzNSwgMjM1LCAxMDAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCBsaW5ld2lkdGggPSAwLjI1LCBsaW5ldHlwZSA9IDIpKSArIGNvb3JkX2ZsaXAoKQ0KcEJhcg0KDQppZiAoc2F2ZXBsb3RzKXsNCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFOb3RpY2VkSW1wdWxzQ29uUGVybWltcC5zdmciLCB3aWR0aD04LCBoZWlnaHQ9MiwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInN2ZyIpKQ0KICB1bmxpbmsoIlB0QU5vdGljZWRJbXB1bHNDb25QZXJtaW1wLnN2ZyIpDQogIA0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QU5vdGljZWRJbXB1bHNDb25QZXJtaW1wLnBkZiIsIHdpZHRoPTgsIGhlaWdodD0yLCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAicGRmIikpDQogIHVubGluaygiUHRBTm90aWNlZEltcHVsc0NvblBlcm1pbXAucGRmIikNCn0NCg0KYGBgDQoNClNlbGVjdGVkIG1ldHJpYw0KDQpgYGB7cn0NCg0KaW1wdWxzVmFyIDwtICJkSW1wdWxzU0hNMDVFeE1heExSIg0KDQpgYGANCg0KIyMjIyBkU1FNIGFuZCBsb3VkbmVzcyBjb21wYXJpc29uDQoNCk5vdyB0aGUgaGlnaGVzdCBpbXBvcnRhbmNlIGRTUU1zIGFyZSByYW5rZWQgYWdhaW5zdCBlYWNoIG90aGVyLCBjb250cm9sbGluZyBmb3IgbG91ZG5lc3MgZGlmZmVyZW5jZS4NCg0KIyMjIyMgSW5jbHVkZSBkdG9uYWwgbG91ZG5lc3MNCg0KIyMjIyMjIFNldCB2YXJpYWJsZXMNCg0KYGBge3J9DQoNCmlWYXJzIDwtIGMoZGlmZlZhciwgZFNoYXJwVmFyLCBkVG9uTGRWYXIsIGRGbHVjdFZhciwgZFJvdWdoVmFyLCBkSW1wdWxzVmFyKQ0KZFZhciA8LSAiTm90aWNlZFBjRmlsdCINCg0Kc2VlZHMgPC0gYyg5ODQ2NSwgNTQxNjMsIDY1NDEsIDM2NDg1LCA4NDk2NzUpDQoNCmBgYA0KDQojIyMjIyMgSHlwZXJwYXJhbWV0ZXIgdHVuaW5nDQoNCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NH0NCg0KcCA8LSBtdHJ5VHVuZShkYXRhSW49c3RpbU5vdGljZURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkPXNlZWRzWzFdLA0KICAgICAgICAgICAgIG50cmVlcz1udHJlZXMsIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KcA0KDQpgYGANCg0KU2VsZWN0ZWQgaHlwZXJwYXJhbWV0ZXJzDQoNCmBgYHtyfQ0KDQpudHJlZSA8LSA1MDENCm10cnkgPC0gYXMuaW50ZWdlcihsZW5ndGgoaVZhcnMpLzEuNzUpDQoNCmBgYA0KDQoNCiMjIyMjIyBSdW4gbW9kZWwNCg0KVHJhaW4gcHJlbGltaW5hcnkgbW9kZWwNCg0KYGBge3J9DQoNCm5wZXJtIDwtIDUNCg0KcmVzdWx0c091dFNRTXMxIDwtIGNyZlJlZyhkYXRhSW49c3RpbU5vdGljZURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkc1sxOjJdLCBudHJlZT1udHJlZSwgbXRyeT1tdHJ5LCBwZXJtSW1wQ29uZFRocmVzPXBlcm1JbXBDb25kVGhyZXMsIG5wZXJtPW5wZXJtLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCg0KIyBwcmludCBtb2RlbCBwcmVkaWN0aW9uIHJlc3VsdHMNCnJlc3VsdHNPdXRTUU1zMSRPT0JfUk1TRQ0KcmVzdWx0c091dFNRTXMxJE9PQl9NQUUNCnJlc3VsdHNPdXRTUU1zMSRSc3F1YXJlZA0KDQpgYGANCg0KVHJhaW4gbXVsdGlwbGUgc2VlZHMgbW9kZWwNCg0KYGBge3J9DQoNCnJlc3VsdHNPdXRTUU1zMSA8LSBtdWx0aV9jcmZSZWcoZGF0YUluPXN0aW1Ob3RpY2VEYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZHM9c2VlZHMsIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dFNRTXMxJE9PQl9STVNFDQpyZXN1bHRzT3V0U1FNczEkT09CX01BRQ0KcmVzdWx0c091dFNRTXMxJFJzcXVhcmVkDQoNCmBgYA0KDQpgYGB7cn0NCg0KIyBzdG9yZSByZXN1bHRzDQpyZXNOb3RpY2VGaXRbJ0RpZmYgU1FNcyBpbmMgdG9uYWwgbG91ZCcsICdSTVNFJ10gPC0gcmVzdWx0c091dFNRTXMxJE9PQl9STVNFDQpyZXNOb3RpY2VGaXRbJ0RpZmYgU1FNcyBpbmMgdG9uYWwgbG91ZCcsICdNQUUnXSA8LSByZXN1bHRzT3V0U1FNczEkT09CX01BRQ0KcmVzTm90aWNlRml0WydEaWZmIFNRTXMgaW5jIHRvbmFsIGxvdWQnLCAnUnNxdWFyZWQnXSA8LSByZXN1bHRzT3V0U1FNczEkUnNxdWFyZWQNCnJlc05vdGljZVBlcm1JbXAkRGlmZlNRTXMxIDwtIHJlc3VsdHNPdXRTUU1zMSRjb25kaXRpb25hbF9wZXJtaW1wDQoNCmBgYA0KDQojIyMjIyMgUGxvdCByZXN1bHRzDQoNCmBgYHtyLCBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTIuNH0NCnBhcihtYWk9YygwLDMsMCwwKSkNCg0KIyBwbG90IGNvbmRpdGlvbmFsIGltcG9ydGFuY2UNCnJlc3VsdHNPdXRTUU1zMS5jb25pbXAgPC0gYXJyYW5nZShyZXN1bHRzT3V0U1FNczEkY29uZGl0aW9uYWxfcGVybWltcCwgZGVzYyhyb3dfbnVtYmVyKCkpKQ0KDQpwQmFyIDwtIGdncGxvdChyZXN1bHRzT3V0U1FNczEuY29uaW1wKSArIGdlb21fY29sKGFlcyh4PWZhY3Rvcihyb3duYW1lcyhyZXN1bHRzT3V0U1FNczEuY29uaW1wKSwgbGV2ZWxzPXJvd25hbWVzKHJlc3VsdHNPdXRTUU1zMS5jb25pbXApKSwgeT1Db25kUGVybUltcCksIGZpbGw9bXljb2xvdXJzWzddLCB3aWR0aD0wLjUpICsgbGFicyh4PSJWYXJpYWJsZSIsIHk9IkNvbmRpdGlvbmFsIHZhcmlhYmxlIHBlcm11dGF0aW9uIGltcG9ydGFuY2UgKCUgVUFTIG5vdGljZWQpIikgKyB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIpLCBwYW5lbC5ncmlkPWVsZW1lbnRfbGluZShjb2xvciA9IHJnYigyMzUsIDIzNSwgMjM1LCAxMDAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCBsaW5ld2lkdGggPSAwLjI1LCBsaW5ldHlwZSA9IDIpKSArIGNvb3JkX2ZsaXAoeWxpbT1jKDAsIDYwMCkpDQpwQmFyDQoNCmlmIChzYXZlcGxvdHMpew0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QU5vdGljZURpZmZTUU1zVG9uTGRDb25QZXJtaW1wLnN2ZyIsIHdpZHRoPTgsIGhlaWdodD0yLjQsIHBhdGg9ZmlsZS5wYXRoKG91dEZpZ1BhdGgsICJzdmciKSkNCiAgdW5saW5rKCJQdEFOb3RpY2VEaWZmU1FNc1RvbkxkQ29uUGVybWltcC5zdmciKQ0KICANCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFOb3RpY2VEaWZmU1FNc1RvbkxkQ29uUGVybWltcC5wZGYiLCB3aWR0aD04LCBoZWlnaHQ9Mi40LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAicGRmIikpDQogIHVubGluaygiUHRBTm90aWNlRGlmZlNRTXNUb25MZENvblBlcm1pbXAucGRmIikNCn0NCg0KYGBgDQoNCiMjIyMjIEV4Y2x1ZGUgdG9uYWwgbG91ZG5lc3MNCg0KIyMjIyMjIFNldCB2YXJpYWJsZXMNCg0KYGBge3J9DQoNCmlWYXJzIDwtIGMoZGlmZlZhciwgZFNoYXJwVmFyLCBkVG9uYWxWYXIsIGRGbHVjdFZhciwgZFJvdWdoVmFyLCBkSW1wdWxzVmFyKQ0KZFZhciA8LSAiTm90aWNlZFBjRmlsdCINCg0Kc2VlZHMgPC0gYyg0OTg2NSwgNzg1MiwgODQ1OTYxLCA0MTA1ODMsIDM2NzQ4KQ0KDQpgYGANCg0KIyMjIyMjIEh5cGVycGFyYW1ldGVyIHR1bmluZw0KDQpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTR9DQoNCnAgPC0gbXRyeVR1bmUoZGF0YUluPXN0aW1Ob3RpY2VEYXRhQU51bSwgaVZhcnM9aVZhcnMsIGRWYXI9ZFZhciwgc2VlZD1zZWVkc1sxXSwNCiAgICAgICAgICAgICBudHJlZXM9bnRyZWVzLCBtaW5zcGxpdD1taW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkNCnANCg0KYGBgDQoNClNlbGVjdGVkIGh5cGVycGFyYW1ldGVycw0KDQpgYGB7cn0NCg0KbnRyZWUgPC0gNDAwMQ0KbXRyeSA8LSBhcy5pbnRlZ2VyKGxlbmd0aChpVmFycykvMS43NSkNCg0KYGBgDQoNCg0KIyMjIyMjIFJ1biBtb2RlbA0KDQpUcmFpbiBwcmVsaW1pbmFyeSBtb2RlbA0KDQpgYGB7cn0NCg0KbnBlcm0gPC0gNQ0KDQpyZXN1bHRzT3V0U1FNczIgPC0gY3JmUmVnKGRhdGFJbj1zdGltTm90aWNlRGF0YUFOdW0sIGlWYXJzPWlWYXJzLCBkVmFyPWRWYXIsIHNlZWRzPXNlZWRzWzE6Ml0sIG50cmVlPW50cmVlLCBtdHJ5PW10cnksIHBlcm1JbXBDb25kVGhyZXM9cGVybUltcENvbmRUaHJlcywgbnBlcm09bnBlcm0sIG1pbnNwbGl0PW1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KQ0KDQojIHByaW50IG1vZGVsIHByZWRpY3Rpb24gcmVzdWx0cw0KcmVzdWx0c091dFNRTXMyJE9PQl9STVNFDQpyZXN1bHRzT3V0U1FNczIkT09CX01BRQ0KcmVzdWx0c091dFNRTXMyJFJzcXVhcmVkDQoNCmBgYA0KDQpUcmFpbiBtdWx0aXBsZSBzZWVkcyBtb2RlbA0KDQpgYGB7cn0NCg0KcmVzdWx0c091dFNRTXMyIDwtIG11bHRpX2NyZlJlZyhkYXRhSW49c3RpbU5vdGljZURhdGFBTnVtLCBpVmFycz1pVmFycywgZFZhcj1kVmFyLCBzZWVkcz1zZWVkcywgbnRyZWU9bnRyZWUsIG10cnk9bXRyeSwgcGVybUltcENvbmRUaHJlcz1wZXJtSW1wQ29uZFRocmVzLCBucGVybT1ucGVybSwgbWluc3BsaXQ9bWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpDQoNCiMgcHJpbnQgbW9kZWwgcHJlZGljdGlvbiByZXN1bHRzDQpyZXN1bHRzT3V0U1FNczIkT09CX1JNU0UNCnJlc3VsdHNPdXRTUU1zMiRPT0JfTUFFDQpyZXN1bHRzT3V0U1FNczIkUnNxdWFyZWQNCg0KYGBgDQoNCmBgYHtyfQ0KDQojIHN0b3JlIHJlc3VsdHMNCnJlc05vdGljZUZpdFsnRGlmZiBTUU1zIG5vIHRvbmFsIGxvdWQnLCAnUk1TRSddIDwtIHJlc3VsdHNPdXRTUU1zMiRPT0JfUk1TRQ0KcmVzTm90aWNlRml0WydEaWZmIFNRTXMgbm8gdG9uYWwgbG91ZCcsICdSTVNFJ10gPC0gcmVzdWx0c091dFNRTXMyJE9PQl9NQUUNCnJlc05vdGljZUZpdFsnRGlmZiBTUU1zIG5vIHRvbmFsIGxvdWQnLCAnUnNxdWFyZWQnXSA8LSByZXN1bHRzT3V0U1FNczIkUnNxdWFyZWQNCnJlc05vdGljZVBlcm1JbXAkRGlmZlNRTXMyIDwtIHJlc3VsdHNPdXRTUU1zMiRjb25kaXRpb25hbF9wZXJtaW1wDQoNCmBgYA0KDQojIyMjIyMgUGxvdCByZXN1bHRzDQoNCmBgYHtyLCBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTIuNH0NCnBhcihtYWk9YygwLDMsMCwwKSkNCg0KIyBwbG90IGNvbmRpdGlvbmFsIGltcG9ydGFuY2UNCnJlc3VsdHNPdXRTUU1zMi5jb25pbXAgPC0gYXJyYW5nZShyZXN1bHRzT3V0U1FNczIkY29uZGl0aW9uYWxfcGVybWltcCwgZGVzYyhyb3dfbnVtYmVyKCkpKQ0KDQpwQmFyIDwtIGdncGxvdChyZXN1bHRzT3V0U1FNczIuY29uaW1wKSArIGdlb21fY29sKGFlcyh4PWZhY3Rvcihyb3duYW1lcyhyZXN1bHRzT3V0U1FNczIuY29uaW1wKSwgbGV2ZWxzPXJvd25hbWVzKHJlc3VsdHNPdXRTUU1zMi5jb25pbXApKSwgeT1Db25kUGVybUltcCksIGZpbGw9bXljb2xvdXJzWzddLCB3aWR0aD0wLjUpICsgbGFicyh4PSJWYXJpYWJsZSIsIHk9IkNvbmRpdGlvbmFsIHZhcmlhYmxlIHBlcm11dGF0aW9uIGltcG9ydGFuY2UgKCUgVUFTIG5vdGljZWQpIikgKyB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIpLCBwYW5lbC5ncmlkPWVsZW1lbnRfbGluZShjb2xvciA9IHJnYigyMzUsIDIzNSwgMjM1LCAxMDAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCBsaW5ld2lkdGggPSAwLjI1LCBsaW5ldHlwZSA9IDIpKSArIGNvb3JkX2ZsaXAoeWxpbT1jKDAsIDYwMCkpDQpwQmFyDQoNCmlmIChzYXZlcGxvdHMpew0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QU5vdGljZURpZmZTUU1zTm9Ub25MZENvblBlcm1pbXAuc3ZnIiwgd2lkdGg9OCwgaGVpZ2h0PTIuNCwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInN2ZyIpKQ0KICB1bmxpbmsoIlB0QU5vdGljZURpZmZTUU1zTm9Ub25MZENvblBlcm1pbXAuc3ZnIikNCiAgDQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBTm90aWNlRGlmZlNRTXNOb1RvbkxkQ29uUGVybWltcC5wZGYiLCB3aWR0aD04LCBoZWlnaHQ9Mi40LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAicGRmIikpDQogIHVubGluaygiUHRBTm90aWNlRGlmZlNRTXNOb1RvbkxkQ29uUGVybWltcC5wZGYiKQ0KfQ0KDQpgYGANCg0KIyMjIFNhdmUgdGhlIHJlc3VsdHMgb3V0cHV0cyB0byBmaWxlDQoNCmBgYHtyfQ0KDQppZiAoc2F2ZWRhdGEpew0KICB1dGlsczo6d3JpdGUuY3N2KHJlc05vdGljZUZpdCwgcGFzdGUob3V0RGF0YVBhdGgsICJcXHB0QUNSRk5vdGljZU9PQkZpdC5jc3YiLCBzZXA9IiIpKQ0KICBpaSA8LSAwDQogIHRlbXAgPSBsaXN0KCkNCiAgZm9yIChyZXMgaW4gcmVzTm90aWNlUGVybUltcCl7DQogICAgaWkgPC0gaWkgKyAxDQogICAgdGVtcFtbaWldXSA8LSBhcy5kYXRhLmZyYW1lKHJlc05vdGljZVBlcm1JbXBbaWldKQ0KICAgIG5hbWVzKHRlbXBbW2lpXV0pIDwtIG5hbWVzKHJlc05vdGljZVBlcm1JbXBbaWldKQ0KICB9DQogIG9wZW54bHN4Ojp3cml0ZS54bHN4KHRlbXAsIHBhc3RlKG91dERhdGFQYXRoLCAiXFxwdEFDUkZOb3RpY2VDb25QZXJtaW1wLnhsc3giLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXA9IiIpLA0KICAgICAgICAgICAgICAgICAgICAgICByb3dOYW1lcz1UUlVFKQ0KfQ0KDQpgYGANCg0KIyMgUGFydCBBIHN1bW1hcnkNCg0KU3VtbWFyeSBvZiByZXN1bHRzIGZvciBQYXJ0IEENCg0KIyMjIFdpdGggdG9uYWwgbG91ZG5lc3MNCg0KIyMjIyBBYnNvbHV0ZSB2YXJpYWJsZXMNCg0KYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTR9DQojIGNvbWJpbmUgdGhlIGFubm95YW5jZSBwZXJtIGltcG9ydGFuY2UgcmVzdWx0cw0KDQojIGNvbnZlcnQgZWFjaCByZXN1bHQgdG8gYSB0aWJibGUgd2l0aCByb3duYW1lcyBhZGRlZCB0byBhIGNvbHVtbiwgcmVuYW1pbmcgdGhlIGRhdGEgY29sdW1uIHRvICdkQW5ub3knIGV0Yy4NCnJlc2RBbm5veU1uQWJzUGVybUltcFRibCA8LSBhcy5kYXRhLmZyYW1lKHJlc2RBbm5veU1uUGVybUltcCRBYnNTUU1zMS9tYXgocmVzZEFubm95TW5QZXJtSW1wJEFic1NRTXMxKSkgfD4NCiAgdGliYmxlOjpyb3duYW1lc190b19jb2x1bW4odmFyPSdWYXJpYWJsZScpDQpjb2xuYW1lcyhyZXNkQW5ub3lNbkFic1Blcm1JbXBUYmwpWzJdIDwtICJkQW5ub3kiDQoNCnJlc2RIaUFubm95QWJzUGVybUltcFRibCA8LSBhcy5kYXRhLmZyYW1lKHJlc2RIaUFubm95UGVybUltcCRBYnNTUU1zMS9tYXgocmVzZEhpQW5ub3lQZXJtSW1wJEFic1NRTXMxKSkgfD4NCiAgdGliYmxlOjpyb3duYW1lc190b19jb2x1bW4odmFyPSdWYXJpYWJsZScpDQpjb2xuYW1lcyhyZXNkSGlBbm5veUFic1Blcm1JbXBUYmwpWzJdIDwtICJkSGlBbm5veSINCg0KcmVzTm90aWNlQWJzUGVybUltcFRibCA8LSBhcy5kYXRhLmZyYW1lKHJlc05vdGljZVBlcm1JbXAkQWJzU1FNczEvbWF4KHJlc05vdGljZVBlcm1JbXAkQWJzU1FNczEpKSB8Pg0KICB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbih2YXI9J1ZhcmlhYmxlJykNCmNvbG5hbWVzKHJlc05vdGljZUFic1Blcm1JbXBUYmwpWzJdIDwtICJkTm90aWNlIg0KDQojIG1lcmdlIHRoZSBkYXRhZnJhbWVzDQpyZXNBYnNQZXJtSW1wVGJsIDwtIGxpc3QocmVzZEFubm95TW5BYnNQZXJtSW1wVGJsLCByZXNkSGlBbm5veUFic1Blcm1JbXBUYmwsIHJlc05vdGljZUFic1Blcm1JbXBUYmwpIHw+DQogIHB1cnJyOjpyZWR1Y2UobWVyZ2UsIGJ5ID0gYygnVmFyaWFibGUnKSwgYWxsID0gVCkNCg0KIyByZW5hbWUgdGhlIGNvbHVtbnMNCmNvbG5hbWVzKHJlc0Fic1Blcm1JbXBUYmwpWzI6NF0gPC0gYygiTWVhbiBjaGFuZ2UgaW4gYW5ub3lhbmNlIiwgIiVIQSBbcChIQSB8IDApXSIsICIlIFVBUyBub3RpY2VkIikNCnJlc0Fic1Blcm1JbXBUYmxbaXMubmEocmVzQWJzUGVybUltcFRibCldIDwtIDANCg0KcmVzQWJzIDwtIHRpZHlyOjpwaXZvdF9sb25nZXIocmVzQWJzUGVybUltcFRibCwgY29scz0tVmFyaWFibGUsIG5hbWVzX3RvPSJPdXRjb21lIiwgdmFsdWVzX3RvPSJJbXAiKQ0KDQojIHJlb3JkZXIgcmVzIHRpYmJsZSwgZGVzY2VuZGluZyBieSB0aGUgdmFyaWFibGUgSW1wIGdyb3VwZWQgc3VtIGFuZCBjcmVhdGUgY29sdW1uIHdpdGggbmV3IGdyb3VwIG9yZGVyIGFzIGEgZmFjdG9yDQpyZXNBYnMgPC0gcmVzQWJzIHw+IG11dGF0ZShWYXJpYWJsZV9zdW0gPSBzdW0oSW1wKSwgLmJ5PVZhcmlhYmxlKSB8PiBhcnJhbmdlKGRlc2MoVmFyaWFibGVfc3VtKSkgfD4gZ3JvdXBfYnkoVmFyaWFibGVfc3VtLCBWYXJpYWJsZSkgfD4NCiAgIG11dGF0ZShPcmRlciA9IGN1cl9ncm91cF9pZCgpKSB8PiBtdXRhdGUoT3JkZXIgPSBhcy5mYWN0b3IoT3JkZXIpKSB8PiBhcnJhbmdlKGRlc2MoT3JkZXIpKQ0KDQojIFJlb3JkZXIgb3V0Y29tZSBsZXZlbHMNCnJlc0FicyRPdXRjb21lIDwtIGZhY3RvcihyZXNBYnMkT3V0Y29tZSwgbGV2ZWxzPWMoIk1lYW4gY2hhbmdlIGluIGFubm95YW5jZSIsICIlSEEgW3AoSEEgfCAwKV0iLCAiJSBVQVMgbm90aWNlZCIpKQ0KDQojIHBsb3QgcmVzIGFzIGhvcml6b250YWwgYmFyIGNoYXJ0LCB3aXRoIEltcCBhcyB5IGF4aXMsIFZhcmlhYmxlIGFzIHggYXhpcywgT3V0Y29tZSBhcyBmaWxsLCBhbmQgVmFyaWFibGVfc3VtIGFzIG9yZGVyLCByZWxhYmVsIHggYXhpcyB3aXRoIFZhcmlhYmxlIG5hbWVzDQpwQmFyIDwtIGdncGxvdChyZXNBYnMpICsgZ2VvbV9jb2woYWVzKGZpbGw9T3V0Y29tZSwgeT1JbXAsIHg9T3JkZXIpLCBjb2xvdXI9J2dyZXkzNScsICB3aWR0aD0wLjc1LCBzaG93LmxlZ2VuZD1UUlVFKSArIGxhYnMoeD0iVmFyaWFibGUiLCB5PSJOb3JtYWxpc2VkIHZhcmlhYmxlIHBlcm11dGF0aW9uIGltcG9ydGFuY2UiKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiksIHBhbmVsLmdyaWQ9ZWxlbWVudF9saW5lKGNvbG9yID0gcmdiKDIzNSwgMjM1LCAyMzUsIDEwMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksIGxpbmV3aWR0aCA9IDAuMjUsIGxpbmV0eXBlID0gMiksIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIpICsgY29vcmRfZmxpcCh5bGltPWMoLTAuMSwgMikpICsgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPW15Y29sb3VycykgKyBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscz11bmlxdWUocmV2KHJlc0FicyRWYXJpYWJsZSkpKQ0KcEJhcg0KDQppZiAoc2F2ZXBsb3RzKXsNCiAgZ2dzYXZlKGZpbGVuYW1lPSJQdEFjcmZBYnNTUU1zU3VtbWFyeS5zdmciLCB3aWR0aD04LCBoZWlnaHQ9NCwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInN2ZyIpKQ0KICB1bmxpbmsoIlB0QWNyZkFic1NRTXNTdW1tYXJ5LnN2ZyIpDQogIA0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWNyZkFic1NRTXNTdW1tYXJ5LnBkZiIsIHdpZHRoPTgsIGhlaWdodD00LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAicGRmIikpDQogIHVubGluaygiUHRBY3JmQWJzU1FNc1N1bW1hcnkucGRmIikNCn0NCg0KYGBgDQojIyMjIERpZmZlcmVuY2UgdmFyaWFibGVzDQoNCmBgYHtyLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD00fQ0KIyBjb21iaW5lIHRoZSBhbm5veWFuY2UgcGVybSBpbXBvcnRhbmNlIHJlc3VsdHMNCg0KIyBjb252ZXJ0IGVhY2ggcmVzdWx0IHRvIGEgdGliYmxlIHdpdGggcm93bmFtZXMgYWRkZWQgdG8gYSBjb2x1bW4sIHJlbmFtaW5nIHRoZSBkYXRhIGNvbHVtbiB0byAnZEFubm95JyBldGMuDQpyZXNkQW5ub3lNbkRpZmZQZXJtSW1wVGJsIDwtIGFzLmRhdGEuZnJhbWUocmVzZEFubm95TW5QZXJtSW1wJERpZmZTUU1zMS9tYXgocmVzZEFubm95TW5QZXJtSW1wJERpZmZTUU1zMSkpIHw+DQogIHRpYmJsZTo6cm93bmFtZXNfdG9fY29sdW1uKHZhcj0nVmFyaWFibGUnKQ0KY29sbmFtZXMocmVzZEFubm95TW5EaWZmUGVybUltcFRibClbMl0gPC0gImRBbm5veSINCg0KcmVzZEhpQW5ub3lEaWZmUGVybUltcFRibCA8LSBhcy5kYXRhLmZyYW1lKHJlc2RIaUFubm95UGVybUltcCREaWZmU1FNczEvbWF4KHJlc2RIaUFubm95UGVybUltcCREaWZmU1FNczEpKSB8Pg0KICB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbih2YXI9J1ZhcmlhYmxlJykNCmNvbG5hbWVzKHJlc2RIaUFubm95RGlmZlBlcm1JbXBUYmwpWzJdIDwtICJkSGlBbm5veSINCg0KcmVzTm90aWNlRGlmZlBlcm1JbXBUYmwgPC0gYXMuZGF0YS5mcmFtZShyZXNOb3RpY2VQZXJtSW1wJERpZmZTUU1zMS9tYXgocmVzTm90aWNlUGVybUltcCREaWZmU1FNczEpKSB8Pg0KICB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbih2YXI9J1ZhcmlhYmxlJykNCmNvbG5hbWVzKHJlc05vdGljZURpZmZQZXJtSW1wVGJsKVsyXSA8LSAiZE5vdGljZSINCg0KIyBtZXJnZSB0aGUgZGF0YWZyYW1lcw0KcmVzRGlmZlBlcm1JbXBUYmwgPC0gbGlzdChyZXNkQW5ub3lNbkRpZmZQZXJtSW1wVGJsLCByZXNkSGlBbm5veURpZmZQZXJtSW1wVGJsLCByZXNOb3RpY2VEaWZmUGVybUltcFRibCkgfD4NCiAgcHVycnI6OnJlZHVjZShtZXJnZSwgYnkgPSBjKCdWYXJpYWJsZScpLCBhbGwgPSBUKQ0KDQojIHJlbmFtZSB0aGUgY29sdW1ucw0KY29sbmFtZXMocmVzRGlmZlBlcm1JbXBUYmwpWzI6NF0gPC0gYygiTWVhbiBjaGFuZ2UgaW4gYW5ub3lhbmNlIiwgIiVIQSBbcChIQSB8IDApXSIsICIlIFVBUyBub3RpY2VkIikNCnJlc0RpZmZQZXJtSW1wVGJsW2lzLm5hKHJlc0RpZmZQZXJtSW1wVGJsKV0gPC0gMA0KDQpyZXNEaWZmIDwtIHRpZHlyOjpwaXZvdF9sb25nZXIocmVzRGlmZlBlcm1JbXBUYmwsIGNvbHM9LVZhcmlhYmxlLCBuYW1lc190bz0iT3V0Y29tZSIsIHZhbHVlc190bz0iSW1wIikNCg0KIyByZW9yZGVyIHJlcyB0aWJibGUsIGRlc2NlbmRpbmcgYnkgdGhlIHZhcmlhYmxlIEltcCBncm91cGVkIHN1bSBhbmQgY3JlYXRlIGNvbHVtbiB3aXRoIG5ldyBncm91cCBvcmRlciBhcyBhIGZhY3Rvcg0KcmVzRGlmZiA8LSByZXNEaWZmIHw+IG11dGF0ZShWYXJpYWJsZV9zdW0gPSBzdW0oSW1wKSwgLmJ5PVZhcmlhYmxlKSB8PiBhcnJhbmdlKGRlc2MoVmFyaWFibGVfc3VtKSkgfD4gZ3JvdXBfYnkoVmFyaWFibGVfc3VtLCBWYXJpYWJsZSkgfD4NCiAgIG11dGF0ZShPcmRlciA9IGN1cl9ncm91cF9pZCgpKSB8PiBtdXRhdGUoT3JkZXIgPSBhcy5mYWN0b3IoT3JkZXIpKSB8PiBhcnJhbmdlKGRlc2MoT3JkZXIpKQ0KDQojIFJlb3JkZXIgb3V0Y29tZSBsZXZlbHMNCnJlc0RpZmYkT3V0Y29tZSA8LSBmYWN0b3IocmVzRGlmZiRPdXRjb21lLCBsZXZlbHM9YygiTWVhbiBjaGFuZ2UgaW4gYW5ub3lhbmNlIiwgIiVIQSBbcChIQSB8IDApXSIsICIlIFVBUyBub3RpY2VkIikpDQoNCiMgcGxvdCByZXMgYXMgaG9yaXpvbnRhbCBiYXIgY2hhcnQsIHdpdGggSW1wIGFzIHkgYXhpcywgVmFyaWFibGUgYXMgeCBheGlzLCBPdXRjb21lIGFzIGZpbGwsIGFuZCBWYXJpYWJsZV9zdW0gYXMgb3JkZXIsIHJlbGFiZWwgeCBheGlzIHdpdGggVmFyaWFibGUgbmFtZXMNCnBCYXIgPC0gZ2dwbG90KHJlc0RpZmYpICsgZ2VvbV9jb2woYWVzKGZpbGw9T3V0Y29tZSwgeT1JbXAsIHg9T3JkZXIpLCBjb2xvdXI9J2dyZXkzNScsICB3aWR0aD0wLjc1LCBzaG93LmxlZ2VuZD1UUlVFKSArIGxhYnMoeD0iVmFyaWFibGUiLCB5PSJOb3JtYWxpc2VkIHZhcmlhYmxlIHBlcm11dGF0aW9uIGltcG9ydGFuY2UiKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiksIHBhbmVsLmdyaWQ9ZWxlbWVudF9saW5lKGNvbG9yID0gcmdiKDIzNSwgMjM1LCAyMzUsIDEwMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksIGxpbmV3aWR0aCA9IDAuMjUsIGxpbmV0eXBlID0gMiksIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIpICsgY29vcmRfZmxpcCh5bGltPWMoLTAuMSwgMikpICsgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPW15Y29sb3VycykgKyBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscz11bmlxdWUocmV2KHJlc0RpZmYkVmFyaWFibGUpKSkNCnBCYXINCg0KaWYgKHNhdmVwbG90cyl7DQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBY3JmRGlmZlNRTXNTdW1tYXJ5LnN2ZyIsIHdpZHRoPTgsIGhlaWdodD00LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAic3ZnIikpDQogIHVubGluaygiUHRBY3JmRGlmZlNRTXNTdW1tYXJ5LnN2ZyIpDQogIA0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWNyZkRpZmZTUU1zU3VtbWFyeS5wZGYiLCB3aWR0aD04LCBoZWlnaHQ9NCwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInBkZiIpKQ0KICB1bmxpbmsoIlB0QWNyZkRpZmZTUU1zU3VtbWFyeS5wZGYiKQ0KfQ0KDQpgYGANCg0KIyMjIE5vIHRvbmFsIGxvdWRuZXNzDQoNCiMjIyMgQWJzb2x1dGUgdmFyaWFibGVzDQoNCmBgYHtyLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD0zLjd9DQojIGNvbWJpbmUgdGhlIGFubm95YW5jZSBwZXJtIGltcG9ydGFuY2UgcmVzdWx0cw0KDQojIGNvbnZlcnQgZWFjaCByZXN1bHQgdG8gYSB0aWJibGUgd2l0aCByb3duYW1lcyBhZGRlZCB0byBhIGNvbHVtbiwgcmVuYW1pbmcgdGhlIGRhdGEgY29sdW1uIHRvICdkQW5ub3knIGV0Yy4NCnJlc2RBbm5veU1uQWJzUGVybUltcE5vVG9uTGRUYmwgPC0gYXMuZGF0YS5mcmFtZShyZXNkQW5ub3lNblBlcm1JbXAkQWJzU1FNczIvbWF4KHJlc2RBbm5veU1uUGVybUltcCRBYnNTUU1zMikpIHw+DQogIHRpYmJsZTo6cm93bmFtZXNfdG9fY29sdW1uKHZhcj0nVmFyaWFibGUnKQ0KY29sbmFtZXMocmVzZEFubm95TW5BYnNQZXJtSW1wTm9Ub25MZFRibClbMl0gPC0gImRBbm5veSINCg0KcmVzZEhpQW5ub3lBYnNQZXJtSW1wTm9Ub25MZFRibCA8LSBhcy5kYXRhLmZyYW1lKHJlc2RIaUFubm95UGVybUltcCRBYnNTUU1zMi9tYXgocmVzZEhpQW5ub3lQZXJtSW1wJEFic1NRTXMyKSkgfD4NCiAgdGliYmxlOjpyb3duYW1lc190b19jb2x1bW4odmFyPSdWYXJpYWJsZScpDQpjb2xuYW1lcyhyZXNkSGlBbm5veUFic1Blcm1JbXBOb1RvbkxkVGJsKVsyXSA8LSAiZEhpQW5ub3kiDQoNCnJlc05vdGljZUFic1Blcm1JbXBOb1RvbkxkVGJsIDwtIGFzLmRhdGEuZnJhbWUocmVzTm90aWNlUGVybUltcCRBYnNTUU1zMi9tYXgocmVzTm90aWNlUGVybUltcCRBYnNTUU1zMikpIHw+DQogIHRpYmJsZTo6cm93bmFtZXNfdG9fY29sdW1uKHZhcj0nVmFyaWFibGUnKQ0KY29sbmFtZXMocmVzTm90aWNlQWJzUGVybUltcE5vVG9uTGRUYmwpWzJdIDwtICJkTm90aWNlIg0KDQojIG1lcmdlIHRoZSBkYXRhZnJhbWVzDQpyZXNBYnNOb1RvbkxkUGVybUltcE5vVG9uTGRUYmwgPC0gbGlzdChyZXNkQW5ub3lNbkFic1Blcm1JbXBOb1RvbkxkVGJsLCByZXNkSGlBbm5veUFic1Blcm1JbXBOb1RvbkxkVGJsLCByZXNOb3RpY2VBYnNQZXJtSW1wTm9Ub25MZFRibCkgfD4NCiAgcHVycnI6OnJlZHVjZShtZXJnZSwgYnkgPSBjKCdWYXJpYWJsZScpLCBhbGwgPSBUKQ0KDQojIHJlbmFtZSB0aGUgY29sdW1ucw0KY29sbmFtZXMocmVzQWJzTm9Ub25MZFBlcm1JbXBOb1RvbkxkVGJsKVsyOjRdIDwtIGMoIk1lYW4gY2hhbmdlIGluIGFubm95YW5jZSIsICIlSEEgW3AoSEEgfCAwKV0iLCAiJSBVQVMgbm90aWNlZCIpDQpyZXNBYnNOb1RvbkxkUGVybUltcE5vVG9uTGRUYmxbaXMubmEocmVzQWJzTm9Ub25MZFBlcm1JbXBOb1RvbkxkVGJsKV0gPC0gMA0KDQpyZXNBYnNOb1RvbkxkIDwtIHRpZHlyOjpwaXZvdF9sb25nZXIocmVzQWJzTm9Ub25MZFBlcm1JbXBOb1RvbkxkVGJsLCBjb2xzPS1WYXJpYWJsZSwgbmFtZXNfdG89Ik91dGNvbWUiLCB2YWx1ZXNfdG89IkltcCIpDQoNCiMgcmVvcmRlciByZXMgdGliYmxlLCBkZXNjZW5kaW5nIGJ5IHRoZSB2YXJpYWJsZSBJbXAgZ3JvdXBlZCBzdW0gYW5kIGNyZWF0ZSBjb2x1bW4gd2l0aCBuZXcgZ3JvdXAgb3JkZXIgYXMgYSBmYWN0b3INCnJlc0Fic05vVG9uTGQgPC0gcmVzQWJzTm9Ub25MZCB8PiBtdXRhdGUoVmFyaWFibGVfc3VtID0gc3VtKEltcCksIC5ieT1WYXJpYWJsZSkgfD4gYXJyYW5nZShkZXNjKFZhcmlhYmxlX3N1bSkpIHw+IGdyb3VwX2J5KFZhcmlhYmxlX3N1bSwgVmFyaWFibGUpIHw+DQogICBtdXRhdGUoT3JkZXIgPSBjdXJfZ3JvdXBfaWQoKSkgfD4gbXV0YXRlKE9yZGVyID0gYXMuZmFjdG9yKE9yZGVyKSkgfD4gYXJyYW5nZShkZXNjKE9yZGVyKSkNCg0KIyBSZW9yZGVyIG91dGNvbWUgbGV2ZWxzDQpyZXNBYnNOb1RvbkxkJE91dGNvbWUgPC0gZmFjdG9yKHJlc0Fic05vVG9uTGQkT3V0Y29tZSwgbGV2ZWxzPWMoIk1lYW4gY2hhbmdlIGluIGFubm95YW5jZSIsICIlSEEgW3AoSEEgfCAwKV0iLCAiJSBVQVMgbm90aWNlZCIpKQ0KDQojIHBsb3QgcmVzIGFzIGhvcml6b250YWwgYmFyIGNoYXJ0LCB3aXRoIEltcCBhcyB5IGF4aXMsIFZhcmlhYmxlIGFzIHggYXhpcywgT3V0Y29tZSBhcyBmaWxsLCBhbmQgVmFyaWFibGVfc3VtIGFzIG9yZGVyLCByZWxhYmVsIHggYXhpcyB3aXRoIFZhcmlhYmxlIG5hbWVzDQpwQmFyIDwtIGdncGxvdChyZXNBYnNOb1RvbkxkKSArIGdlb21fY29sKGFlcyhmaWxsPU91dGNvbWUsIHk9SW1wLCB4PU9yZGVyKSwgY29sb3VyPSdncmV5MzUnLCAgd2lkdGg9MC43NSwgc2hvdy5sZWdlbmQ9VFJVRSkgKyBsYWJzKHg9IlZhcmlhYmxlIiwgeT0iTm9ybWFsaXNlZCB2YXJpYWJsZSBwZXJtdXRhdGlvbiBpbXBvcnRhbmNlIikgKyB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIpLCBwYW5lbC5ncmlkPWVsZW1lbnRfbGluZShjb2xvciA9IHJnYigyMzUsIDIzNSwgMjM1LCAxMDAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCBsaW5ld2lkdGggPSAwLjI1LCBsaW5ldHlwZSA9IDIpLCBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKSArIGNvb3JkX2ZsaXAoeWxpbT1jKC0wLjEsIDIpKSArIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1teWNvbG91cnMpICsgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHM9dW5pcXVlKHJldihyZXNBYnNOb1RvbkxkJFZhcmlhYmxlKSkpDQpwQmFyDQoNCmlmIChzYXZlcGxvdHMpew0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWNyZkFic1NRTXNOb1RvbkxkU3VtbWFyeS5zdmciLCB3aWR0aD04LCBoZWlnaHQ9My43LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAic3ZnIikpDQogIHVubGluaygiUHRBY3JmQWJzU1FNc05vVG9uTGRTdW1tYXJ5LnN2ZyIpDQogIA0KICBnZ3NhdmUoZmlsZW5hbWU9IlB0QWNyZkFic1NRTXNOb1RvbkxkU3VtbWFyeS5wZGYiLCB3aWR0aD04LCBoZWlnaHQ9My43LCBwYXRoPWZpbGUucGF0aChvdXRGaWdQYXRoLCAicGRmIikpDQogIHVubGluaygiUHRBY3JmQWJzU1FNc05vVG9uTGRTdW1tYXJ5LnBkZiIpDQp9DQoNCmBgYA0KIyMjIyBEaWZmZXJlbmNlIHZhcmlhYmxlcw0KDQpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9NH0NCiMgY29tYmluZSB0aGUgYW5ub3lhbmNlIHBlcm0gaW1wb3J0YW5jZSByZXN1bHRzDQoNCiMgY29udmVydCBlYWNoIHJlc3VsdCB0byBhIHRpYmJsZSB3aXRoIHJvd25hbWVzIGFkZGVkIHRvIGEgY29sdW1uLCByZW5hbWluZyB0aGUgZGF0YSBjb2x1bW4gdG8gJ2RBbm5veScgZXRjLg0KcmVzZEFubm95TW5EaWZmUGVybUltcE5vVG9uTGRUYmwgPC0gYXMuZGF0YS5mcmFtZShyZXNkQW5ub3lNblBlcm1JbXAkRGlmZlNRTXMyL21heChyZXNkQW5ub3lNblBlcm1JbXAkRGlmZlNRTXMyKSkgfD4NCiAgdGliYmxlOjpyb3duYW1lc190b19jb2x1bW4odmFyPSdWYXJpYWJsZScpDQpjb2xuYW1lcyhyZXNkQW5ub3lNbkRpZmZQZXJtSW1wTm9Ub25MZFRibClbMl0gPC0gImRBbm5veSINCg0KcmVzZEhpQW5ub3lEaWZmUGVybUltcE5vVG9uTGRUYmwgPC0gYXMuZGF0YS5mcmFtZShyZXNkSGlBbm5veVBlcm1JbXAkRGlmZlNRTXMyL21heChyZXNkSGlBbm5veVBlcm1JbXAkRGlmZlNRTXMyKSkgfD4NCiAgdGliYmxlOjpyb3duYW1lc190b19jb2x1bW4odmFyPSdWYXJpYWJsZScpDQpjb2xuYW1lcyhyZXNkSGlBbm5veURpZmZQZXJtSW1wTm9Ub25MZFRibClbMl0gPC0gImRIaUFubm95Ig0KDQpyZXNOb3RpY2VEaWZmUGVybUltcE5vVG9uTGRUYmwgPC0gYXMuZGF0YS5mcmFtZShyZXNOb3RpY2VQZXJtSW1wJERpZmZTUU1zMi9tYXgocmVzTm90aWNlUGVybUltcCREaWZmU1FNczIpKSB8Pg0KICB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbih2YXI9J1ZhcmlhYmxlJykNCmNvbG5hbWVzKHJlc05vdGljZURpZmZQZXJtSW1wTm9Ub25MZFRibClbMl0gPC0gImROb3RpY2UiDQoNCiMgbWVyZ2UgdGhlIGRhdGFmcmFtZXMNCnJlc0RpZmZOb1RvbkxkUGVybUltcE5vVG9uTGRUYmwgPC0gbGlzdChyZXNkQW5ub3lNbkRpZmZQZXJtSW1wTm9Ub25MZFRibCwgcmVzZEhpQW5ub3lEaWZmUGVybUltcE5vVG9uTGRUYmwsIHJlc05vdGljZURpZmZQZXJtSW1wTm9Ub25MZFRibCkgfD4NCiAgcHVycnI6OnJlZHVjZShtZXJnZSwgYnkgPSBjKCdWYXJpYWJsZScpLCBhbGwgPSBUKQ0KDQojIHJlbmFtZSB0aGUgY29sdW1ucw0KY29sbmFtZXMocmVzRGlmZk5vVG9uTGRQZXJtSW1wTm9Ub25MZFRibClbMjo0XSA8LSBjKCJNZWFuIGNoYW5nZSBpbiBhbm5veWFuY2UiLCAiJUhBIFtwKEhBIHwgMCldIiwgIiUgVUFTIG5vdGljZWQiKQ0KcmVzRGlmZk5vVG9uTGRQZXJtSW1wTm9Ub25MZFRibFtpcy5uYShyZXNEaWZmTm9Ub25MZFBlcm1JbXBOb1RvbkxkVGJsKV0gPC0gMA0KDQpyZXNEaWZmTm9Ub25MZCA8LSB0aWR5cjo6cGl2b3RfbG9uZ2VyKHJlc0RpZmZOb1RvbkxkUGVybUltcE5vVG9uTGRUYmwsIGNvbHM9LVZhcmlhYmxlLCBuYW1lc190bz0iT3V0Y29tZSIsIHZhbHVlc190bz0iSW1wIikNCg0KIyByZW9yZGVyIHJlcyB0aWJibGUsIGRlc2NlbmRpbmcgYnkgdGhlIHZhcmlhYmxlIEltcCBncm91cGVkIHN1bSBhbmQgY3JlYXRlIGNvbHVtbiB3aXRoIG5ldyBncm91cCBvcmRlciBhcyBhIGZhY3Rvcg0KcmVzRGlmZk5vVG9uTGQgPC0gcmVzRGlmZk5vVG9uTGQgfD4gbXV0YXRlKFZhcmlhYmxlX3N1bSA9IHN1bShJbXApLCAuYnk9VmFyaWFibGUpIHw+IGFycmFuZ2UoZGVzYyhWYXJpYWJsZV9zdW0pKSB8PiBncm91cF9ieShWYXJpYWJsZV9zdW0sIFZhcmlhYmxlKSB8Pg0KICAgbXV0YXRlKE9yZGVyID0gY3VyX2dyb3VwX2lkKCkpIHw+IG11dGF0ZShPcmRlciA9IGFzLmZhY3RvcihPcmRlcikpIHw+IGFycmFuZ2UoZGVzYyhPcmRlcikpDQoNCiMgUmVvcmRlciBvdXRjb21lIGxldmVscw0KcmVzRGlmZk5vVG9uTGQkT3V0Y29tZSA8LSBmYWN0b3IocmVzRGlmZk5vVG9uTGQkT3V0Y29tZSwgbGV2ZWxzPWMoIk1lYW4gY2hhbmdlIGluIGFubm95YW5jZSIsICIlSEEgW3AoSEEgfCAwKV0iLCAiJSBVQVMgbm90aWNlZCIpKQ0KDQojIHBsb3QgcmVzIGFzIGhvcml6b250YWwgYmFyIGNoYXJ0LCB3aXRoIEltcCBhcyB5IGF4aXMsIFZhcmlhYmxlIGFzIHggYXhpcywgT3V0Y29tZSBhcyBmaWxsLCBhbmQgVmFyaWFibGVfc3VtIGFzIG9yZGVyLCByZWxhYmVsIHggYXhpcyB3aXRoIFZhcmlhYmxlIG5hbWVzDQpwQmFyIDwtIGdncGxvdChyZXNEaWZmTm9Ub25MZCkgKyBnZW9tX2NvbChhZXMoZmlsbD1PdXRjb21lLCB5PUltcCwgeD1PcmRlciksIGNvbG91cj0nZ3JleTM1JywgIHdpZHRoPTAuNzUsIHNob3cubGVnZW5kPVRSVUUpICsgbGFicyh4PSJWYXJpYWJsZSIsIHk9Ik5vcm1hbGlzZWQgdmFyaWFibGUgcGVybXV0YXRpb24gaW1wb3J0YW5jZSIpICsgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2VyaWYiKSwgcGFuZWwuZ3JpZD1lbGVtZW50X2xpbmUoY29sb3IgPSByZ2IoMjM1LCAyMzUsIDIzNSwgMTAwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgbGluZXdpZHRoID0gMC4yNSwgbGluZXR5cGUgPSAyKSwgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikgKyBjb29yZF9mbGlwKHlsaW09YygtMC4xLCAyKSkgKyBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9bXljb2xvdXJzKSArIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzPXVuaXF1ZShyZXYocmVzRGlmZk5vVG9uTGQkVmFyaWFibGUpKSkNCnBCYXINCg0KaWYgKHNhdmVwbG90cyl7DQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBY3JmRGlmZlNRTXNOb1RvbkxkU3VtbWFyeS5zdmciLCB3aWR0aD04LCBoZWlnaHQ9NCwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInN2ZyIpKQ0KICB1bmxpbmsoIlB0QWNyZkRpZmZTUU1zTm9Ub25MZFN1bW1hcnkuc3ZnIikNCiAgDQogIGdnc2F2ZShmaWxlbmFtZT0iUHRBY3JmRGlmZlNRTXNOb1RvbkxkU3VtbWFyeS5wZGYiLCB3aWR0aD04LCBoZWlnaHQ9NCwgcGF0aD1maWxlLnBhdGgob3V0RmlnUGF0aCwgInBkZiIpKQ0KICB1bmxpbmsoIlB0QWNyZkRpZmZTUU1zTm9Ub25MZFN1bW1hcnkucGRmIikNCn0NCg0KYGBgDQoNCiMjIyBTYXZlIHRoZSByZXN1bHRzIG91dHB1dHMgdG8gZmlsZQ0KDQpgYGB7cn0NCiMgTWFrZSBhIGxpc3Qgb2YgdGhlIHN1bW1hcnkgcmVzdWx0cw0KcmVzU3VtbWFyeSA8LSBsaXN0KHJlc0FicywgcmVzRGlmZiwgcmVzQWJzTm9Ub25MZCwgcmVzRGlmZk5vVG9uTGQpDQoNCiMgU2F2ZSB0aGUgcmVzdWx0cw0KaWYgKHNhdmVkYXRhKXsNCiAgaWkgPC0gMA0KICB0ZW1wID0gbGlzdCgpDQogIGZvciAocmVzIGluIHJlc1N1bW1hcnkpew0KICAgIGlpIDwtIGlpICsgMQ0KICAgIHRlbXBbW2lpXV0gPC0gZGF0YS5mcmFtZShyZXNTdW1tYXJ5W2lpXSkNCiAgfQ0KICBvcGVueGxzeDo6d3JpdGUueGxzeCh0ZW1wLCBwYXN0ZShvdXREYXRhUGF0aCwgIlxccHRBQ1JGU3VtbWFyeS54bHN4IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VwPSIiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgcm93TmFtZXM9VFJVRSkNCn0NCg0KYGBg